merged latest
diff --git a/README.txt b/README.txt
deleted file mode 100644
index c765eba..0000000
--- a/README.txt
+++ /dev/null
@@ -1,136 +0,0 @@
-Overview:
- 
-jclouds allows provisioning and control of cloud resources, including blobstore
-and compute, from Java and Clojure.  Our API gives allows developers to use
-both portable abstractions and cloud-specific features.  We test support of 30
-cloud providers and cloud software stacks, including Amazon, Azure, GoGrid,
-Ninefold, OpenStack, and vCloud.  jclouds is licensed under the Apache License,
-Version 2.0
- 
-our current version is 1.4.2
-our next maintenance version is 1.4.2-SNAPSHOT
-our dev version is 1.5.0-SNAPSHOT
- 
-check out our examples site! https://github.com/jclouds/jclouds-examples
-
-our compute api supports: aws-ec2, gogrid, cloudservers-us, stub (in-memory), deltacloud,
-                          cloudservers-uk, vcloud (generic), ec2 (generic), byon, nova,
-                          trmk-ecloud, trmk-vcloudexpress, eucalyptus (generic)
-                          cloudsigma-zrh, elasticstack(generic), go2cloud-jhb1, cloudsigma-lvs,
-                          bluelock-vcloud-zone01, stratogen-vcloud-mycloud, rimuhosting,
-                          slicehost, eucalyptus-partnercloud-ec2, elastichosts-lon-p (Peer 1), 
-                          elastichosts-sat-p (Peer 1), elastichosts-lon-b (BlueSquare),
-                          openhosting-east1, serverlove-z1-man, skalicloud-sdg-my,
-                          greenhousedata-element-vcloud, softlayer, cloudsigma (generic),
-                          cloudstack (generic), ninefold-compute, openstack-nov (keystone),
-                          hpcloud-compute, trystack-nova, openstack-nova-ec2,
-                          rackspace-cloudservers-us (next gen), rackspace-cloudservers-uk (next gen)
-
-  * note * the pom dependency org.jclouds/jclouds-allcompute gives you access to
-           to all of these providers
-
-our blobstore api supports: aws-s3, cloudfiles-us, cloudfiles-uk, filesystem,
-                            azureblob, atmos (generic), synaptic-storage, hpcloud-objectstorage,
-                            cloudonestorage, walrus(generic), ninefold-storage,
-                            eucalyptus-partnercloud-s3, swift (generic), transient (in-mem)
- 
-  * note * the pom dependency org.jclouds/jclouds-allblobstore gives you access to
-           to all of these providers
-
-our loadbalancer api supports: cloudloadbalancers-us
- 
-  * note * the pom dependency org.jclouds/jclouds-allloadbalancer gives you access to
-           to all of these providers
-
-we also have aws-cloudwatch support.
-
-we also have support for: ibmdev, mezeo, nirvanix, boxdotnet, openstack nova, scality ring,
-                          hosteurope-storage, tiscali-storage, scaleup-storage, googlestorage,
-                          azurequeue, simpledb, as well as a async-http-client
-                          driver in the sandbox
-
-
-If you want access to all jclouds components, include the maven dependency org.jclouds/jclouds-all
-
-
-BlobStore Example (Java):
-  // init
-  context = new BlobStoreContextFactory().createContext(
-                  "aws-s3",
-                  accesskeyid,
-                  secretaccesskey);
-  blobStore = context.getBlobStore();
- 
-  // create container
-  blobStore.createContainerInLocation(null, "mycontainer");
-  
-  // add blob
-  blob = blobStore.blobBuilder("test").payload("testdata").build();
-  blobStore.putBlob("mycontainer", blob);
-
-BlobStore Example (Clojure):
-  (use 'org.jclouds.blobstore2)
-
-  (def *blobstore* (blobstore "azureblob" account encodedkey))
-  (create-container *blobstore* "mycontainer")
-  (put-blob *blobstore* "mycontainer" (blob "test" :payload "testdata"))
-
-Compute Example (Java):
-  // init
-  context = new ComputeServiceContextFactory().createContext(
-                  "aws-ec2",
-                  accesskeyid,
-                  secretaccesskey,
-                  ImmutableSet.of(new Log4JLoggingModule(),
-                                  new SshjSshClientModule()));
-  client = context.getComputeService();
- 
-  // define the requirements of your node
-  template = client.templateBuilder().osFamily(UBUNTU).smallest().build();
-
-  // setup a boot user which is the same as your login
-  template.getOptions().runScript(AdminAccess.standard());
- 
-  // these nodes will be accessible via ssh when the call returns
-  nodes = client.createNodesInGroup("mycluster", 2, template);
-
-  // you can now run ad-hoc commands on the nodes based on predicates
-  responses = client.runScriptOnNodesMatching(inGroup("mycluster"), "uptime",
-                  wrapInInitScript(false));
-
-Compute Example (Clojure):
-  (use 'org.jclouds.compute2)
-
-  ; create a compute service using sshj and log4j extensions
-  (def compute 
-    (*compute* "trmk`-ecloud" "user" "password" :sshj :log4j))
-
-  ; launch a couple nodes with the default operating system, installing your user.
-  (create-nodes *compute* "mycluster" 2
-    (TemplateOptions$Builder/runScript (AdminAccess/standard)))
- 
-  ; run a command on that group
-  (run-script-on-nodes-matching *compute* (in-group? "mycluster") "uptime" 
-    (RunScriptOptions$Builder/wrapInInitScript false))
-
-Downloads:
-  * release notes: http://www.jclouds.org/documentation/releasenotes/1.3
-  * installation guide: http://www.jclouds.org/documentation/userguide/installation-guide
-  * maven repo: http://repo2.maven.org/maven2 (maven central - the default repository)
-  * snapshot repo: https://oss.sonatype.org/content/repositories/snapshots
- 
-Links:
-  * project page: http://jclouds.org/
-  * documentation: http://www.jclouds.org/documentation/index
-  * javadocs (1.1.0): http://jclouds.rimuhosting.com/apidocs/
-  * javadocs (1.0-SNAPSHOT): http://jclouds.rimuhosting.com/apidocs-SNAPSHOT/
-  * community: http://www.jclouds.org/documentation/reference/apps-that-use-jclouds
-  * user group: http://groups.google.com/group/jclouds
-  * dev group: http://groups.google.com/group/jclouds-dev
-  * twitter: http://twitter.com/jclouds
-
-## License
-
-Copyright (C) 2009-2012 jclouds, Inc.
-
-Licensed under the Apache License, Version 2.0
diff --git a/all/pom.xml b/all/pom.xml
index c0ed79d..cfd5ff3 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -41,6 +41,11 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
+            <groupId>org.jclouds.provider</groupId>
+            <artifactId>aws-sqs</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>jclouds-allloadbalancer</artifactId>
             <version>${project.version}</version>
diff --git a/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosBlobRequestSigner.java b/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosBlobRequestSigner.java
index 0fe231f..1d211bc 100644
--- a/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosBlobRequestSigner.java
+++ b/apis/atmos/src/main/java/org/jclouds/atmos/blobstore/AtmosBlobRequestSigner.java
@@ -68,11 +68,21 @@
    }
 
    @Override
+   public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signPutBlob(String container, Blob blob) {
       return cleanRequest(processor.createRequest(createMethod, container, blobToObject.apply(blob)));
    }
 
    @Override
+   public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signRemoveBlob(String container, String name) {
       return cleanRequest(processor.createRequest(deleteMethod, getPath(container, name)));
    }
diff --git a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/CloudFilesAsyncClient.java b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/CloudFilesAsyncClient.java
index 14e3b28..6e2ca5a 100644
--- a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/CloudFilesAsyncClient.java
+++ b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/CloudFilesAsyncClient.java
@@ -19,10 +19,12 @@
 package org.jclouds.cloudfiles;
 
 import java.net.URI;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.HEAD;
 import javax.ws.rs.HeaderParam;
@@ -33,6 +35,7 @@
 import javax.ws.rs.core.MediaType;
 
 import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
+import org.jclouds.cloudfiles.binders.BindIterableToHeadersWithPurgeCDNObjectEmail;
 import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
 import org.jclouds.cloudfiles.functions.ParseCdnUriFromHeaders;
 import org.jclouds.cloudfiles.functions.ParseContainerCDNMetadataFromHeaders;
@@ -41,6 +44,7 @@
 import org.jclouds.openstack.filters.AuthenticateRequest;
 import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
 import org.jclouds.openstack.swift.Storage;
+import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.Endpoint;
 import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.Headers;
@@ -57,7 +61,7 @@
  * All commands return a ListenableFuture of the result from Cloud Files. Any exceptions incurred
  * during processing will be backend in an {@link ExecutionException} as documented in
  * {@link ListenableFuture#get()}.
- * 
+ *
  * @see CloudFilesClient
  * @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" />
  * @author Adrian Cole
@@ -77,9 +81,6 @@
    @Endpoint(CDNManagement.class)
    ListenableFuture<? extends Set<ContainerCDNMetadata>> listCDNContainers(ListCdnContainerOptions... options);
 
-   // TODO: Container name is not included in CDN HEAD response headers, so we
-   // cannot populate it
-   // here.
    /**
     * @see CloudFilesClient#getCDNMetadata
     */
@@ -91,6 +92,18 @@
    ListenableFuture<ContainerCDNMetadata> getCDNMetadata(@PathParam("container") String container);
 
    /**
+    * @see CloudFilesClient#enableCDN(String, long, boolean);
+    */
+   @PUT
+   @Path("/{container}")
+   @Headers(keys = CloudFilesHeaders.CDN_ENABLED, values = "True")
+   @ResponseParser(ParseCdnUriFromHeaders.class)
+   @Endpoint(CDNManagement.class)
+   ListenableFuture<URI> enableCDN(@PathParam("container") String container,
+                                   @HeaderParam(CloudFilesHeaders.CDN_TTL) long ttl,
+                                   @HeaderParam(CloudFilesHeaders.CDN_LOG_RETENTION) boolean logRetention);
+
+   /**
     * @see CloudFilesClient#enableCDN(String, long);
     */
    @PUT
@@ -99,7 +112,7 @@
    @ResponseParser(ParseCdnUriFromHeaders.class)
    @Endpoint(CDNManagement.class)
    ListenableFuture<URI> enableCDN(@PathParam("container") String container,
-            @HeaderParam(CloudFilesHeaders.CDN_TTL) long ttl);
+                                   @HeaderParam(CloudFilesHeaders.CDN_TTL) long ttl);
 
    /**
     * @see CloudFilesClient#enableCDN(String)
@@ -112,14 +125,35 @@
    ListenableFuture<URI> enableCDN(@PathParam("container") String container);
 
    /**
-    * @see CloudFilesClient#updateCDN
+    * @see CloudFilesClient#updateCDN(long, boolean)
     */
    @POST
    @Path("/{container}")
    @ResponseParser(ParseCdnUriFromHeaders.class)
    @Endpoint(CDNManagement.class)
    ListenableFuture<URI> updateCDN(@PathParam("container") String container,
-            @HeaderParam(CloudFilesHeaders.CDN_TTL) long ttl);
+                                   @HeaderParam(CloudFilesHeaders.CDN_TTL) long ttl,
+                                   @HeaderParam(CloudFilesHeaders.CDN_LOG_RETENTION) boolean logRetention);
+
+   /**
+    * @see CloudFilesClient#updateCDN(boolean)
+    */
+   @POST
+   @Path("/{container}")
+   @ResponseParser(ParseCdnUriFromHeaders.class)
+   @Endpoint(CDNManagement.class)
+   ListenableFuture<URI> updateCDN(@PathParam("container") String container,
+                                   @HeaderParam(CloudFilesHeaders.CDN_LOG_RETENTION) boolean logRetention);
+
+   /**
+    * @see CloudFilesClient#updateCDN(long)
+    */
+   @POST
+   @Path("/{container}")
+   @ResponseParser(ParseCdnUriFromHeaders.class)
+   @Endpoint(CDNManagement.class)
+   ListenableFuture<URI> updateCDN(@PathParam("container") String container,
+                                   @HeaderParam(CloudFilesHeaders.CDN_TTL) long ttl);
 
    /**
     * @see CloudFilesClient#disableCDN
@@ -130,4 +164,41 @@
    @Endpoint(CDNManagement.class)
    ListenableFuture<Boolean> disableCDN(@PathParam("container") String container);
 
+   /**
+    * @see CloudFilesClient#purgeCDNObject(String, String, List)
+    */
+   @DELETE
+   @Path("/{container}/{object}")
+   @Headers(keys = CloudFilesHeaders.CDN_CONTAINER_PURGE_OBJECT_EMAIL, values = "{email}")
+   @Endpoint(CDNManagement.class)
+   ListenableFuture<Boolean> purgeCDNObject(@PathParam("container") String container, 
+                                            @PathParam("object") String object,
+                                            @BinderParam(BindIterableToHeadersWithPurgeCDNObjectEmail.class) Iterable<String> emails);
+
+   /**
+    * @see CloudFilesClient#purgeCDNObject(String, String)
+    */
+   @DELETE
+   @Path("/{container}/{object}")
+   @Endpoint(CDNManagement.class)
+   ListenableFuture<Boolean> purgeCDNObject(@PathParam("container") String container, 
+                                            @PathParam("object") String object);
+
+   /**
+    * @see CloudFilesClient#setCDNStaticWebsiteIndex
+    */
+   @POST
+   @Path("/{container}")
+   @Headers(keys = CloudFilesHeaders.CDN_WEBSITE_INDEX, values = "{index}")
+   ListenableFuture<Boolean> setCDNStaticWebsiteIndex(@PathParam("container") String container,
+                                                      @PathParam("index") String index);
+
+   /**
+    * @see CloudFilesClient#setCDNStaticWebsiteError
+    */
+   @POST
+   @Path("/{container}")
+   @Headers(keys = CloudFilesHeaders.CDN_WEBSITE_ERROR, values = "{error}")
+   ListenableFuture<Boolean> setCDNStaticWebsiteError(@PathParam("container") String container,
+                                                      @PathParam("error") String error);
 }
diff --git a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/CloudFilesClient.java b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/CloudFilesClient.java
index e74ca1e..8a40c3e 100644
--- a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/CloudFilesClient.java
+++ b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/CloudFilesClient.java
@@ -34,22 +34,75 @@
  * <p/>
  * All commands return a Future of the result from Cloud Files. Any exceptions incurred during
  * processing will be backend in an {@link ExecutionException} as documented in {@link Future#get()}.
- * 
- * @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" />
+ *
  * @author Adrian Cole
+ * @see <a href="http://www.rackspacecloud.com/cf-devguide-20090812.pdf" />
  */
 @Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
 public interface CloudFilesClient extends CommonSwiftClient {
+
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/List_CDN-Enabled_Containers-d1e2414.html
+    */
    Set<ContainerCDNMetadata> listCDNContainers(ListCdnContainerOptions... options);
 
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/List_CDN-Enabled_Container_Metadata-d1e2711.html
+    */
    ContainerCDNMetadata getCDNMetadata(String container);
 
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/CDN-Enabled_Container-d1e2665.html
+    */
+   URI enableCDN(String container, long ttl, boolean logRetention);
+
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/CDN-Enabled_Container-d1e2665.html
+    */
    URI enableCDN(String container, long ttl);
-
+   
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/CDN-Enabled_Container-d1e2665.html
+    */
    URI enableCDN(String container);
+   
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/Update_CDN-Enabled_Container_Metadata-d1e2787.html
+    */
+   URI updateCDN(String container, long ttl, boolean logRetention);
 
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/Update_CDN-Enabled_Container_Metadata-d1e2787.html
+    */
+   URI updateCDN(String container, boolean logRetention);
+
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/Update_CDN-Enabled_Container_Metadata-d1e2787.html
+    */
    URI updateCDN(String container, long ttl);
 
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/CDN-Enabled_Container-d1e2665.html
+    */
    boolean disableCDN(String container);
+   
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/Purge_CDN-Enabled_Objects-d1e3858.html
+    */
+   boolean purgeCDNObject(String container, String object, Iterable<String> emails);
+   
+   /**
+    * See http://docs.rackspace.com/files/api/v1/cf-devguide/content/Purge_CDN-Enabled_Objects-d1e3858.html
+    */
+   boolean purgeCDNObject(String container, String object);
 
+   /**
+    * http://docs.rackspace.com/files/api/v1/cf-devguide/content/Create_Static_Website-dle4000.html
+    */
+   boolean setCDNStaticWebsiteIndex(String container, String index);
+
+   /*
+    * http://docs.rackspace.com/files/api/v1/cf-devguide/content/Set_Error_Pages_for_Static_Website-dle4005.html
+    */
+   boolean setCDNStaticWebsiteError(String container, String error);
 }
diff --git a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/binders/BindIterableToHeadersWithPurgeCDNObjectEmail.java b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/binders/BindIterableToHeadersWithPurgeCDNObjectEmail.java
new file mode 100644
index 0000000..77c36a9
--- /dev/null
+++ b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/binders/BindIterableToHeadersWithPurgeCDNObjectEmail.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.cloudfiles.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import javax.inject.Singleton;
+
+import org.jclouds.cloudfiles.reference.CloudFilesHeaders;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMultimap;
+
+/**
+ * @author Everett Toews
+ */
+@Singleton
+public class BindIterableToHeadersWithPurgeCDNObjectEmail implements Binder {
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      checkArgument(checkNotNull(input, "input") instanceof Iterable<?>, "this binder is only valid for Iterable!");
+      checkNotNull(request, "request");
+
+      Iterable<String> emails = (Iterable<String>) input;
+      String emailCSV = Joiner.on(", ").join((List<String>) emails);
+      ImmutableMultimap<String, String> headers = 
+    		  ImmutableMultimap.<String, String> of(CloudFilesHeaders.CDN_CONTAINER_PURGE_OBJECT_EMAIL, emailCSV);
+      
+      return (R) request.toBuilder().replaceHeaders(headers).build();
+   }
+}
diff --git a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/config/CloudFilesBlobStoreContextModule.java b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/config/CloudFilesBlobStoreContextModule.java
index c9b64d1..edacb1d 100644
--- a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/config/CloudFilesBlobStoreContextModule.java
+++ b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/blobstore/config/CloudFilesBlobStoreContextModule.java
@@ -23,12 +23,16 @@
 
 import javax.inject.Singleton;
 
+import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.cloudfiles.CloudFilesClient;
+import org.jclouds.openstack.swift.TemporaryUrlKey;
 import org.jclouds.cloudfiles.blobstore.CloudFilesAsyncBlobStore;
 import org.jclouds.cloudfiles.blobstore.CloudFilesBlobStore;
 import org.jclouds.cloudfiles.blobstore.functions.CloudFilesObjectToBlobMetadata;
 import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
+import org.jclouds.date.TimeStamp;
 import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore;
+import org.jclouds.openstack.swift.blobstore.SwiftBlobRequestSigner;
 import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
 import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
 import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
@@ -39,7 +43,6 @@
 import com.google.inject.Provides;
 
 /**
- * 
  * @author Adrian Cole
  */
 public class CloudFilesBlobStoreContextModule extends SwiftBlobStoreContextModule {
@@ -67,5 +70,6 @@
       bind(SwiftBlobStore.class).to(CloudFilesBlobStore.class);
       bind(SwiftAsyncBlobStore.class).to(CloudFilesAsyncBlobStore.class);
       bind(ObjectToBlobMetadata.class).to(CloudFilesObjectToBlobMetadata.class);
+      bind(BlobRequestSigner.class).to(SwiftBlobRequestSigner.class);
    }
 }
diff --git a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/domain/ContainerCDNMetadata.java b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/domain/ContainerCDNMetadata.java
index 727cf23..a885ecb 100644
--- a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/domain/ContainerCDNMetadata.java
+++ b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/domain/ContainerCDNMetadata.java
@@ -29,17 +29,22 @@
 
    private String name;
    private boolean cdn_enabled;
+   private boolean log_retention;
    private long ttl;
    private URI cdn_uri;
+   private URI cdn_ssl_uri;
+   private URI cdn_streaming_uri;
    private String referrer_acl;
    private String useragent_acl;
-   private boolean log_retention;
 
-   public ContainerCDNMetadata(String name, boolean cdnEnabled, long ttl, URI cdnUri) {
+   public ContainerCDNMetadata(String name, boolean cdnEnabled, boolean logRetention, long ttl, URI cdnUri, URI cdnSslUri, URI cdnStreamingUri) {
       this.name = name;
       this.cdn_enabled = cdnEnabled;
+      this.log_retention = logRetention;
       this.ttl = ttl;
       this.cdn_uri = cdnUri;
+      this.cdn_ssl_uri = cdnSslUri;
+      this.cdn_streaming_uri = cdnStreamingUri;
    }
 
    public ContainerCDNMetadata() {
@@ -53,16 +58,36 @@
       return name;
    }
 
-   public URI getCDNUri() {
-      return cdn_uri;
+   public boolean isCDNEnabled() {
+      return cdn_enabled;
+   }
+
+   public boolean isLogRetention() {
+      return log_retention;
    }
 
    public long getTTL() {
       return ttl;
    }
 
-   public boolean isCDNEnabled() {
-      return cdn_enabled;
+   public URI getCDNUri() {
+      return cdn_uri;
+   }
+
+   public URI getCDNSslUri() {
+      return cdn_ssl_uri;
+   }
+
+   public URI getCDNStreamingUri() {
+      return cdn_streaming_uri;
+   }
+
+   public String getReferrerACL() {
+      return referrer_acl;
+   }
+
+   public String getUseragentACL() {
+      return useragent_acl;
    }
 
    public int compareTo(ContainerCDNMetadata o) {
@@ -87,31 +112,21 @@
          return false;
       if (getClass() != obj.getClass())
          return false;
+      
       ContainerCDNMetadata other = (ContainerCDNMetadata) obj;
       if (cdn_uri == null) {
          if (other.cdn_uri != null)
             return false;
       } else if (!cdn_uri.equals(other.cdn_uri))
          return false;
+      
       return true;
    }
 
-   public String getReferrerACL() {
-      return referrer_acl;
-   }
-
-   public String getUseragentACL() {
-      return useragent_acl;
-   }
-
-   public boolean isLogRetention() {
-      return log_retention;
-   }
-
    @Override
    public String toString() {
       return String.format(
-               "[name=%s, cdn_uri=%s, cdn_enabled=%s, log_retention=%s, referrer_acl=%s, ttl=%s, useragent_acl=%s]",
-               name, cdn_uri, cdn_enabled, log_retention, referrer_acl, ttl, useragent_acl);
+               "[name=%s, cdn_enabled=%s, log_retention=%s, ttl=%s, cdn_uri=%s, cdn_ssl_uri=%s, cdn_streaming_uri=%s, referrer_acl=%s, useragent_acl=%s]",
+                 name, cdn_enabled, log_retention, ttl, cdn_uri, cdn_ssl_uri, cdn_streaming_uri, referrer_acl, useragent_acl);
    }
 }
diff --git a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/functions/ParseContainerCDNMetadataFromHeaders.java b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/functions/ParseContainerCDNMetadataFromHeaders.java
index b53a414..42b9f89 100644
--- a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/functions/ParseContainerCDNMetadataFromHeaders.java
+++ b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/functions/ParseContainerCDNMetadataFromHeaders.java
@@ -45,18 +45,26 @@
     * parses the http response headers to create a new {@link ContainerCDNMetadata} object.
     */
    public ContainerCDNMetadata apply(final HttpResponse from) {
-      String cdnUri = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI),
-               CloudFilesHeaders.CDN_URI);
-      String cdnTTL = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_TTL),
-               CloudFilesHeaders.CDN_TTL);
-      String cdnEnabled = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_ENABLED),
-               CloudFilesHeaders.CDN_ENABLED);
+      String cdnEnabled = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_ENABLED), CloudFilesHeaders.CDN_ENABLED);
+      String cdnLogRetention = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_LOG_RETENTION), CloudFilesHeaders.CDN_LOG_RETENTION);
+      String cdnTTL = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_TTL), CloudFilesHeaders.CDN_TTL);
+      String cdnUri = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_URI), CloudFilesHeaders.CDN_URI);
+      String cdnSslUri = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_SSL_URI), CloudFilesHeaders.CDN_SSL_URI);
+      String cdnStreamingUri = checkNotNull(from.getFirstHeaderOrNull(CloudFilesHeaders.CDN_STREAMING_URI), CloudFilesHeaders.CDN_STREAMING_URI);
+      
       if (cdnUri == null) {
          // CDN is not, and has never, been enabled for this container.
          return null;
-      } else {
-         return new ContainerCDNMetadata(request.getEndpoint().getPath(), Boolean
-                  .parseBoolean(cdnEnabled), Long.parseLong(cdnTTL), URI.create(cdnUri));
+      } 
+      else {
+         return new ContainerCDNMetadata(
+            request.getEndpoint().getPath(), 
+            Boolean.parseBoolean(cdnEnabled), 
+            Boolean.parseBoolean(cdnLogRetention), 
+            Long.parseLong(cdnTTL), 
+            URI.create(cdnUri),
+            URI.create(cdnSslUri),
+            URI.create(cdnStreamingUri));
       }
    }
 
diff --git a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/reference/CloudFilesHeaders.java b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/reference/CloudFilesHeaders.java
index 696398f..e3fbf27 100644
--- a/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/reference/CloudFilesHeaders.java
+++ b/apis/cloudfiles/src/main/java/org/jclouds/cloudfiles/reference/CloudFilesHeaders.java
@@ -31,8 +31,15 @@
 public interface CloudFilesHeaders extends SwiftHeaders {
 
    public static final String CDN_ENABLED = "X-CDN-Enabled";
-   public static final String CDN_REFERRER_ACL = "X-Referrer-ACL ";
+   public static final String CDN_LOG_RETENTION = "X-Log-Retention";
    public static final String CDN_TTL = "X-TTL";
    public static final String CDN_URI = "X-CDN-URI";
+   public static final String CDN_SSL_URI = "X-Cdn-Ssl-Uri";
+   public static final String CDN_STREAMING_URI = "X-Cdn-Streaming-Uri";
+   public static final String CDN_REFERRER_ACL = "X-Referrer-ACL ";
    public static final String CDN_USER_AGENT_ACL = "X-User-Agent-ACL";
+
+   public static final String CDN_CONTAINER_PURGE_OBJECT_EMAIL = "X-Purge-Email";
+   public static final String CDN_WEBSITE_INDEX = "X-Container-Meta-Web-Index";
+   public static final String CDN_WEBSITE_ERROR = "X-Container-Meta-Web-Error";
 }
diff --git a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/CloudFilesClientExpectTest.java b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/CloudFilesClientExpectTest.java
index f69f2c2..cd9b699 100644
--- a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/CloudFilesClientExpectTest.java
+++ b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/CloudFilesClientExpectTest.java
@@ -18,7 +18,16 @@
  */
 package org.jclouds.cloudfiles;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+
+import org.jclouds.blobstore.ContainerNotFoundException;
+import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
 import org.jclouds.cloudfiles.internal.BaseCloudFilesRestClientExpectTest;
+import org.jclouds.cloudfiles.reference.CloudFilesHeaders;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
 import org.testng.annotations.Test;
@@ -30,7 +39,8 @@
 @Test(groups = "unit", testName = "CloudFilesClientExpectTest")
 public class CloudFilesClientExpectTest extends BaseCloudFilesRestClientExpectTest {
 
-   public void deleteContainerReturnsTrueOn200And404() {
+   @Test
+   public void testDeleteContainerReturnsTrueOn200And404() {
 
       HttpRequest deleteContainer = HttpRequest
                .builder()
@@ -50,7 +60,194 @@
       CloudFilesClient clientWhenContainerDoesntExist = requestsSendResponses(initialAuth, responseWithAuth, deleteContainer,
                containerNotFound);
       assert clientWhenContainerDoesntExist.deleteContainerIfEmpty("container");
-
    }
 
+   @Test
+   public void testGetCDNMetadataWhenResponseIs2xxReturnsContainerCDNMetadata() {
+	   HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("HEAD")
+            .endpoint("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .addHeader(CloudFilesHeaders.CDN_ENABLED, "True")
+            .addHeader(CloudFilesHeaders.CDN_LOG_RETENTION, "True")
+            .addHeader(CloudFilesHeaders.CDN_TTL, "259200")
+            .addHeader(CloudFilesHeaders.CDN_URI, "http://546406d62bf471d7435d-36c33e76d676c80251b3c13ecb603b67.r19.cf1.rackcdn.com")
+            .addHeader(CloudFilesHeaders.CDN_SSL_URI, "https://e9f6fe92d217dc013369-36c33e76d676c80251b3c13ecb603b67.ssl.cf1.rackcdn.com")
+            .addHeader(CloudFilesHeaders.CDN_STREAMING_URI, "http://0e79346bc0a2564dcc5e-36c33e76d676c80251b3c13ecb603b67.r19.stream.cf1.rackcdn.com")
+            .statusCode(204)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      ContainerCDNMetadata containerCDNMetadata = cdnContainerClient.getCDNMetadata("container");
+      assertTrue(containerCDNMetadata.isCDNEnabled());
+      assertTrue(containerCDNMetadata.isLogRetention());
+      assertEquals(containerCDNMetadata.getTTL(), 259200);
+      assertEquals(containerCDNMetadata.getCDNUri().toString(), "http://546406d62bf471d7435d-36c33e76d676c80251b3c13ecb603b67.r19.cf1.rackcdn.com");
+      assertEquals(containerCDNMetadata.getCDNSslUri().toString(), "https://e9f6fe92d217dc013369-36c33e76d676c80251b3c13ecb603b67.ssl.cf1.rackcdn.com");
+      assertEquals(containerCDNMetadata.getCDNStreamingUri().toString(), "http://0e79346bc0a2564dcc5e-36c33e76d676c80251b3c13ecb603b67.r19.stream.cf1.rackcdn.com");
+   }
+
+   @Test
+   public void testGetCDNMetadataWhenResponseIs404ReturnsNull() {
+	   HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("HEAD")
+            .endpoint("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .statusCode(404)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      assertNull(cdnContainerClient.getCDNMetadata("container"));
+   }
+
+   @Test
+   public void testUpdateCDNMetadataWhenResponseIs2xxReturnsURI() {
+	   HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("POST")
+            .endpoint("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
+            .addHeader(CloudFilesHeaders.CDN_LOG_RETENTION, "true")
+            .addHeader(CloudFilesHeaders.CDN_TTL, "259200")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .addHeader(CloudFilesHeaders.CDN_ENABLED, "True")
+            .addHeader(CloudFilesHeaders.CDN_LOG_RETENTION, "True")
+            .addHeader(CloudFilesHeaders.CDN_TTL, "259200")
+            .addHeader(CloudFilesHeaders.CDN_URI, "http://546406d62bf471d7435d-36c33e76d676c80251b3c13ecb603b67.r19.cf1.rackcdn.com")
+            .addHeader(CloudFilesHeaders.CDN_SSL_URI, "https://e9f6fe92d217dc013369-36c33e76d676c80251b3c13ecb603b67.ssl.cf1.rackcdn.com")
+            .addHeader(CloudFilesHeaders.CDN_STREAMING_URI, "http://0e79346bc0a2564dcc5e-36c33e76d676c80251b3c13ecb603b67.r19.stream.cf1.rackcdn.com")
+            .statusCode(204)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      URI cdnURI = cdnContainerClient.updateCDN("container", 259200, true);
+      assertEquals(cdnURI.toString(), "http://546406d62bf471d7435d-36c33e76d676c80251b3c13ecb603b67.r19.cf1.rackcdn.com");
+   }
+
+   @Test(expectedExceptions = ContainerNotFoundException.class)
+   public void testUpdateCDNMetadataWhenResponseIs404ThrowsException() {
+      HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("POST")
+            .endpoint("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
+            .addHeader(CloudFilesHeaders.CDN_LOG_RETENTION, "true")
+            .addHeader(CloudFilesHeaders.CDN_TTL, "259200")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .statusCode(404)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      cdnContainerClient.updateCDN("container", 259200, true);
+   }
+   
+   @Test
+   public void testPurgeCDNObjectWhenResponseIs2xxReturnsTrue() {
+	   HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("DELETE")
+            .endpoint("https://cdn3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container/foo.txt")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .statusCode(204)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      assertTrue(cdnContainerClient.purgeCDNObject("container", "foo.txt"));
+   }  
+
+   @Test
+   public void testSetCDNStaticWebsiteIndexWhenResponseIs2xxReturnsTrue() {
+	   HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("POST")
+            .endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
+            .addHeader(CloudFilesHeaders.CDN_WEBSITE_INDEX, "index.html")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .statusCode(204)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      assertTrue(cdnContainerClient.setCDNStaticWebsiteIndex("container", "index.html"));
+   }
+
+   @Test(expectedExceptions = ContainerNotFoundException.class)
+   public void testSetCDNStaticWebsiteIndexWhenResponseIs404ThrowsException() {
+	   HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("POST")
+            .endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
+            .addHeader(CloudFilesHeaders.CDN_WEBSITE_INDEX, "index.html")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .statusCode(404)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      cdnContainerClient.setCDNStaticWebsiteIndex("container", "index.html");
+   }
+
+   @Test
+   public void testSetCDNStaticWebsiteErrorWhenResponseIs2xxReturnsTrue() {
+	   HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("POST")
+            .endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
+            .addHeader(CloudFilesHeaders.CDN_WEBSITE_ERROR, "error.html")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .statusCode(204)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      assertTrue(cdnContainerClient.setCDNStaticWebsiteError("container", "error.html"));
+   }
+
+   @Test(expectedExceptions = ContainerNotFoundException.class)
+   public void testSetCDNStaticWebsiteErrorWhenResponseIs404ThrowsException() {
+	   HttpRequest cdnContainerRequest = HttpRequest.builder()
+            .method("POST")
+            .endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container")
+            .addHeader(CloudFilesHeaders.CDN_WEBSITE_ERROR, "error.html")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse cdnContainerResponse = HttpResponse.builder()
+            .statusCode(404)
+            .build();
+
+      CloudFilesClient cdnContainerClient = requestsSendResponses(
+            initialAuth, responseWithAuth, cdnContainerRequest, cdnContainerResponse);
+
+      cdnContainerClient.setCDNStaticWebsiteError("container", "error.html");
+   }
 }
\ No newline at end of file
diff --git a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/CloudFilesClientLiveTest.java b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/CloudFilesClientLiveTest.java
index b39533b..b7a22c9 100644
--- a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/CloudFilesClientLiveTest.java
+++ b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/CloudFilesClientLiveTest.java
@@ -27,6 +27,7 @@
 import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
 import org.jclouds.cloudfiles.options.ListCdnContainerOptions;
 import org.jclouds.openstack.swift.CommonSwiftClientLiveTest;
+import org.jclouds.openstack.swift.domain.ContainerMetadata;
 import org.jclouds.openstack.swift.domain.SwiftObject;
 import org.testng.annotations.Test;
 
@@ -80,16 +81,23 @@
          cdnMetadata = getApi().getCDNMetadata(containerNameWithCDN);
 
          assertTrue(cdnMetadata.isCDNEnabled());
-
          assertEquals(cdnMetadata.getCDNUri(), cdnUri);
          
+         // Test static website metadata
+         getApi().setCDNStaticWebsiteIndex(containerNameWithCDN, "index.html");
+         getApi().setCDNStaticWebsiteError(containerNameWithCDN, "error.html");
+         
+         ContainerMetadata containerMetadata = getApi().getContainerMetadata(containerNameWithCDN);
+         
+         assertEquals(containerMetadata.getMetadata().get("web-index"), "index.html");
+         assertEquals(containerMetadata.getMetadata().get("web-error"), "error.html");
          
          cdnMetadata = getApi().getCDNMetadata(containerNameWithoutCDN);
          assert cdnMetadata == null || !cdnMetadata.isCDNEnabled() : containerNameWithoutCDN
                   + " should not have metadata";
 
          assert getApi().getCDNMetadata("DoesNotExist") == null;
-
+         
          // List CDN metadata for containers, and ensure all CDN info is
          // available for enabled
          // container
@@ -97,9 +105,16 @@
          assertTrue(cdnMetadataList.size() >= 1);
 
          cdnMetadata = getApi().getCDNMetadata(containerNameWithCDN);
+         final boolean cdnEnabled = cdnMetadata.isCDNEnabled();
+         final boolean logRetention = cdnMetadata.isLogRetention();
          final long initialTTL = cdnMetadata.getTTL();
-         assertTrue(cdnMetadataList.contains(new ContainerCDNMetadata(containerNameWithCDN, true, initialTTL, cdnUri)));
+         final URI cdnSslUri = cdnMetadata.getCDNSslUri();
+         final URI cdnStreamingUri = cdnMetadata.getCDNStreamingUri();
+         assertTrue(cdnMetadataList.contains(new ContainerCDNMetadata(
+            containerNameWithCDN, cdnEnabled, logRetention, initialTTL, cdnUri, cdnSslUri, cdnStreamingUri)));
 
+         
+         
          // Test listing with options
          cdnMetadataList = getApi().listCDNContainers(ListCdnContainerOptions.Builder.enabledOnly());
          assertTrue(Iterables.all(cdnMetadataList, new Predicate<ContainerCDNMetadata>() {
@@ -113,10 +128,9 @@
                            containerNameWithCDN.substring(0, containerNameWithCDN.length() - 1)).maxResults(1));
          assertEquals(cdnMetadataList.size(), 1);
 
-         // Enable CDN with PUT for the same container, this time with a custom
-         // TTL
+         // Enable CDN with PUT for the same container, this time with a custom TTL and Log Retention
          long ttl = 4000;
-         getApi().enableCDN(containerNameWithCDN, ttl);
+         getApi().enableCDN(containerNameWithCDN, ttl, true);
 
          cdnMetadata = getApi().getCDNMetadata(containerNameWithCDN);
 
@@ -126,7 +140,7 @@
 
          // Check POST by updating TTL settings
          ttl = minimumTTL;
-         getApi().updateCDN(containerNameWithCDN, minimumTTL);
+         getApi().updateCDN(containerNameWithCDN, minimumTTL, false);
 
          cdnMetadata = getApi().getCDNMetadata(containerNameWithCDN);
          assertTrue(cdnMetadata.isCDNEnabled());
@@ -135,9 +149,15 @@
 
          // Confirm that minimum allowed value for TTL is 3600, lower values are
          // ignored.
-         getApi().updateCDN(containerNameWithCDN, 3599L);
+         getApi().updateCDN(containerNameWithCDN, 3599L, false);
          cdnMetadata = getApi().getCDNMetadata(containerNameWithCDN);
          assertEquals(cdnMetadata.getTTL(), 3599L);
+         
+         // Test purging an object from a CDN container
+         SwiftObject swiftObject = newSwiftObject("hello", "hello.txt");
+         getApi().putObject(containerNameWithCDN, swiftObject);
+         
+         assertTrue(getApi().purgeCDNObject(containerNameWithCDN, swiftObject.getInfo().getName()));
 
          // Disable CDN with POST
          assertTrue(getApi().disableCDN(containerNameWithCDN));
diff --git a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/binders/BindIterableToHeadersWithPurgeCDNObjectEmailTest.java b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/binders/BindIterableToHeadersWithPurgeCDNObjectEmailTest.java
new file mode 100644
index 0000000..66d4f21
--- /dev/null
+++ b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/binders/BindIterableToHeadersWithPurgeCDNObjectEmailTest.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.cloudfiles.binders;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.jclouds.cloudfiles.reference.CloudFilesHeaders;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.openstack.swift.CommonSwiftClientTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Tests behavior of {@code BindIterableToHeadersWithPurgeCDNObjectEmail}
+ * 
+ * @author Everett Toews
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
+@Test(groups = "unit", testName = "BindIterableToHeadersWithPurgeCDNObjectEmailTest")
+public class BindIterableToHeadersWithPurgeCDNObjectEmailTest extends CommonSwiftClientTest {
+
+   @Test
+   public void testEmailBind() {
+      List<String> emails = ImmutableList.of("foo@bar.com", "bar@foo.com");
+
+      HttpRequest request = HttpRequest.builder().method("DELETE").endpoint("http://localhost").build();
+      BindIterableToHeadersWithPurgeCDNObjectEmail binder = 
+         injector.getInstance(BindIterableToHeadersWithPurgeCDNObjectEmail.class);
+      
+      HttpRequest actualRequest = binder.bindToRequest(request, emails);
+      HttpRequest expectedRequest = HttpRequest.builder()
+         .method("DELETE")
+         .endpoint("http://localhost")
+         .addHeader(CloudFilesHeaders.CDN_CONTAINER_PURGE_OBJECT_EMAIL, "foo@bar.com, bar@foo.com")
+         .build(); 
+
+      assertEquals(actualRequest, expectedRequest);
+   }
+
+   @Test(expectedExceptions = NullPointerException.class)
+   public void testNullListIsBad() {
+      HttpRequest request = HttpRequest.builder().method("DELETE").endpoint("http://localhost").build();
+      BindIterableToHeadersWithPurgeCDNObjectEmail binder = 
+         injector.getInstance(BindIterableToHeadersWithPurgeCDNObjectEmail.class);
+      
+      binder.bindToRequest(request, null);
+   }
+
+   @Test(expectedExceptions = NullPointerException.class)
+   public void testNullRequestIsBad() {
+      List<String> emails = ImmutableList.of("foo@bar.com", "bar@foo.com");
+      BindIterableToHeadersWithPurgeCDNObjectEmail binder = 
+         injector.getInstance(BindIterableToHeadersWithPurgeCDNObjectEmail.class);
+      
+      binder.bindToRequest(null, emails);
+   }
+}
diff --git a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/blobstore/integration/CloudFilesBlobLiveTest.java b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/blobstore/integration/CloudFilesBlobLiveTest.java
index edae3c1..360c307 100644
--- a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/blobstore/integration/CloudFilesBlobLiveTest.java
+++ b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/blobstore/integration/CloudFilesBlobLiveTest.java
@@ -19,15 +19,36 @@
 package org.jclouds.cloudfiles.blobstore.integration;
 
 import org.jclouds.openstack.swift.blobstore.integration.SwiftBlobLiveTest;
+import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
 import org.testng.annotations.Test;
 
+import java.util.UUID;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
 /**
- * 
  * @author Adrian Cole
  */
-@Test(groups = { "live" })
+@Test(groups = {"live"})
 public class CloudFilesBlobLiveTest extends SwiftBlobLiveTest {
-   public CloudFilesBlobLiveTest(){
+
+   public CloudFilesBlobLiveTest() {
       provider = "cloudfiles";
    }
+
+   public void testGetAndSetTemporaryUrlKey() {
+      TemporaryUrlKeyApi client = view.utils().injector().getInstance(TemporaryUrlKeyApi.class);
+
+      String currentSecretKey = client.getTemporaryUrlKey();
+      assertNotNull(currentSecretKey);
+      try {
+         String testKey = UUID.randomUUID().toString();
+         client.setTemporaryUrlKey(testKey);
+         assertEquals(client.getTemporaryUrlKey(), testKey);
+
+      } finally {
+         client.setTemporaryUrlKey(currentSecretKey);
+      }
+   }
 }
diff --git a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/blobstore/integration/CloudFilesBlobSignerLiveTest.java b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/blobstore/integration/CloudFilesBlobSignerLiveTest.java
index 7add9a2..d67142e 100644
--- a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/blobstore/integration/CloudFilesBlobSignerLiveTest.java
+++ b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/blobstore/integration/CloudFilesBlobSignerLiveTest.java
@@ -22,12 +22,11 @@
 import org.testng.annotations.Test;
 
 /**
- * 
  * @author Adrian Cole
  */
-@Test(groups = { "live" })
+@Test(groups = {"live"})
 public class CloudFilesBlobSignerLiveTest extends SwiftBlobSignerLiveTest {
-   public CloudFilesBlobSignerLiveTest(){
+   public CloudFilesBlobSignerLiveTest() {
       provider = "cloudfiles";
    }
 }
diff --git a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/functions/ParseContainerCDNMetadataListFromJsonResponseTest.java b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/functions/ParseContainerCDNMetadataListFromJsonResponseTest.java
index 42837ba..235fb27 100644
--- a/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/functions/ParseContainerCDNMetadataListFromJsonResponseTest.java
+++ b/apis/cloudfiles/src/test/java/org/jclouds/cloudfiles/functions/ParseContainerCDNMetadataListFromJsonResponseTest.java
@@ -51,12 +51,32 @@
 
       InputStream is = getClass().getResourceAsStream("/test_list_cdn.json");
       Set<ContainerCDNMetadata> expects = ImmutableSortedSet.of(
-
-      new ContainerCDNMetadata("adriancole-blobstore.testCDNOperationsContainerWithCDN", false, 3600, URI
-               .create("http://c0354712.cdn.cloudfiles.rackspacecloud.com")), new ContainerCDNMetadata(
-               "adriancole-blobstore5", true, 28800, URI.create("http://c0404671.cdn.cloudfiles.rackspacecloud.com")),
-               new ContainerCDNMetadata("adriancole-cfcdnint.testCDNOperationsContainerWithCDN", false, 3600, URI
-                        .create("http://c0320431.cdn.cloudfiles.rackspacecloud.com")));
+         new ContainerCDNMetadata(
+            "adriancole-blobstore.testCDNOperationsContainerWithCDN", 
+            false, 
+            false,
+            3600, 
+            URI.create("http://c0354712.cdn.cloudfiles.rackspacecloud.com"), 
+            URI.create("https://c0354712.cdn.ssl.cloudfiles.rackspacecloud.com"),
+            URI.create("http://c0354712.cdn.stream.cloudfiles.rackspacecloud.com")),
+         new ContainerCDNMetadata(
+            "adriancole-blobstore5", 
+            true, 
+            false,
+            28800, 
+            URI.create("http://c0404671.cdn.cloudfiles.rackspacecloud.com"),
+            URI.create("https://c0404671.cdn.ssl.cloudfiles.rackspacecloud.com"),
+            URI.create("http://c0404671.cdn.stream.cloudfiles.rackspacecloud.com")),
+         new ContainerCDNMetadata(
+            "adriancole-cfcdnint.testCDNOperationsContainerWithCDN", 
+            false, 
+            false,
+            3600, 
+            URI.create("http://c0320431.cdn.cloudfiles.rackspacecloud.com"),
+            URI.create("https://c0320431.cdn.ssl.cloudfiles.rackspacecloud.com"),
+            URI.create("http://c0320431.cdn.stream.cloudfiles.rackspacecloud.com"))
+      );
+      
       ParseJson<SortedSet<ContainerCDNMetadata>> parser = i.getInstance(Key
                .get(new TypeLiteral<ParseJson<SortedSet<ContainerCDNMetadata>>>() {
                }));
diff --git a/apis/cloudfiles/src/test/resources/test_list_cdn.json b/apis/cloudfiles/src/test/resources/test_list_cdn.json
index bea7be8..9562816 100644
--- a/apis/cloudfiles/src/test/resources/test_list_cdn.json
+++ b/apis/cloudfiles/src/test/resources/test_list_cdn.json
@@ -1,5 +1,35 @@
 [
-{"name":"adriancole-blobstore.testCDNOperationsContainerWithCDN","cdn_enabled":"false","ttl":3600,"cdn_uri":"http://c0354712.cdn.cloudfiles.rackspacecloud.com","referrer_acl":"","useragent_acl":"", "log_retention":"false"},
-{"name":"adriancole-blobstore5","cdn_enabled":"true","ttl":28800,"cdn_uri":"http://c0404671.cdn.cloudfiles.rackspacecloud.com","referrer_acl":"","useragent_acl":"", "log_retention":"false"},
-{"name":"adriancole-cfcdnint.testCDNOperationsContainerWithCDN","cdn_enabled":"false","ttl":3600,"cdn_uri":"http://c0320431.cdn.cloudfiles.rackspacecloud.com","referrer_acl":"","useragent_acl":"", "log_retention":"false"}
+    {
+        "name":"adriancole-blobstore.testCDNOperationsContainerWithCDN",
+        "cdn_enabled":"false",
+        "log_retention":"false",
+        "ttl":3600,
+        "cdn_uri":"http://c0354712.cdn.cloudfiles.rackspacecloud.com",
+        "cdn_ssl_uri":"https://c0354712.cdn.ssl.cloudfiles.rackspacecloud.com",
+        "cdn_streaming_uri":"http://c0354712.cdn.stream.cloudfiles.rackspacecloud.com",
+        "referrer_acl":"",
+        "useragent_acl":""
+    },
+    {
+        "name":"adriancole-blobstore5",
+        "cdn_enabled":"true",
+        "log_retention":"false",
+        "ttl":28800,
+        "cdn_uri":"http://c0404671.cdn.cloudfiles.rackspacecloud.com",
+        "cdn_ssl_uri":"https://c0404671.cdn.ssl.cloudfiles.rackspacecloud.com",
+        "cdn_streaming_uri":"http://c0404671.cdn.stream.cloudfiles.rackspacecloud.com",
+        "referrer_acl":"",
+        "useragent_acl":""
+    },
+    {
+        "name":"adriancole-cfcdnint.testCDNOperationsContainerWithCDN",
+        "cdn_enabled":"false",
+        "log_retention":"false",
+        "ttl":3600,
+        "cdn_uri":"http://c0320431.cdn.cloudfiles.rackspacecloud.com",
+        "cdn_ssl_uri":"https://c0320431.cdn.ssl.cloudfiles.rackspacecloud.com",
+        "cdn_streaming_uri":"http://c0320431.cdn.stream.cloudfiles.rackspacecloud.com",
+        "referrer_acl":"",
+        "useragent_acl":""
+    }
 ]
\ No newline at end of file
diff --git a/apis/cloudsigma/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceLiveTest.java b/apis/cloudsigma/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceLiveTest.java
index bbedf65..5a882ff 100644
--- a/apis/cloudsigma/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceLiveTest.java
+++ b/apis/cloudsigma/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaComputeServiceLiveTest.java
@@ -25,12 +25,13 @@
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.inject.Module;
 
 /**
  * @author Adrian Cole
  */
-@Test(groups = "live")
+@Test(groups = "live", testName = "CloudSigmaComputeServiceLiveTest")
 public class CloudSigmaComputeServiceLiveTest extends BaseComputeServiceLiveTest {
 
    public CloudSigmaComputeServiceLiveTest() {
@@ -46,14 +47,21 @@
    @Override
    protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
       assert node.getUserMetadata().equals(ImmutableMap.<String, String> of()) : String.format(
-            "node userMetadata did not match %s %s", userMetadata, node);
+               "node userMetadata did not match %s %s", userMetadata, node);
    }
-   
+
+   // cloudsigma does not support tags
+   @Override
+   protected void checkTagsInNodeEquals(final NodeMetadata node, final ImmutableSet<String> tags) {
+      assert node.getTags().equals(ImmutableSet.<String> of()) : String.format("node tags did not match %s %s", tags,
+               node);
+   }
+
    protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) {
       // hostname is not predictable based on node metadata
       assert execResponse.getOutput().trim().equals("ubuntu");
    }
-   
+
    @Override
    public void testOptionToNotBlock() {
       // start call has to block until we have a pool of reserved pre-cloned drives.
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApiMetadata.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApiMetadata.java
index cdb671f..d0bf37c 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApiMetadata.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/CloudStackApiMetadata.java
@@ -23,6 +23,7 @@
 
 import org.jclouds.apis.ApiMetadata;
 import org.jclouds.cloudstack.compute.config.CloudStackComputeServiceContextModule;
+import org.jclouds.cloudstack.config.CloudStackParserModule;
 import org.jclouds.cloudstack.config.CloudStackRestClientModule;
 import org.jclouds.rest.RestContext;
 import org.jclouds.rest.internal.BaseRestApiMetadata;
@@ -91,7 +92,10 @@
          .version("2.2")
          .view(TypeToken.of(CloudStackContext.class))
          .defaultProperties(CloudStackApiMetadata.defaultProperties())
-         .defaultModules(ImmutableSet.<Class<? extends Module>>of(CloudStackRestClientModule.class, CloudStackComputeServiceContextModule.class));
+         .defaultModules(ImmutableSet.<Class<? extends Module>> builder()
+                                     .add(CloudStackParserModule.class)
+                                     .add(CloudStackRestClientModule.class)
+                                     .add(CloudStackComputeServiceContextModule.class).build());
       }
       
       @Override
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackDateAdapter.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackDateAdapter.java
deleted file mode 100644
index e0bc79b..0000000
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackDateAdapter.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.cloudstack.config;
-
-import java.io.IOException;
-import java.util.Date;
-
-import javax.inject.Inject;
-
-import org.jclouds.date.DateService;
-import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
-
-import com.google.gson.stream.JsonReader;
-
-/**
- * Data adapter for the date formats used by CloudStack.
- *
- * Essentially this is a workaround for the CloudStack getUsage() API call returning a
- * corrupted form of ISO-8601 dates, which have an unexpected pair of apostrophes, like
- * 2011-12-12'T'00:00:00+00:00
- *
- * @author Richard Downer
- */
-public class CloudStackDateAdapter extends Iso8601DateAdapter {
-
-   @Inject
-   private CloudStackDateAdapter(DateService dateService) {
-      super(dateService);
-   }
-
-   public Date read(JsonReader reader) throws IOException {
-      return parseDate(reader.nextString().replaceAll("'T'", "T"));
-   }
-
-}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackParserModule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackParserModule.java
new file mode 100644
index 0000000..086529f
--- /dev/null
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackParserModule.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.cloudstack.config;
+
+import java.io.IOException;
+import java.util.Date;
+
+import javax.inject.Inject;
+
+import org.jclouds.date.DateService;
+import org.jclouds.json.config.GsonModule.DateAdapter;
+import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
+import org.jclouds.json.internal.IgnoreNullIterableTypeAdapterFactory;
+
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableSet;
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+import com.google.inject.AbstractModule;
+
+/**
+ * @author Adrian Cole
+ */
+public class CloudStackParserModule extends AbstractModule {
+
+   @Override
+   protected void configure() {
+      bind(DateAdapter.class).to(CloudStackDateAdapter.class);
+      bind(IgnoreNullIterableTypeAdapterFactory.class).to(CommaDelimitedOKIgnoreNullIterableTypeAdapterFactory.class);
+   }
+
+   /**
+    * Data adapter for the date formats used by CloudStack.
+    * 
+    * Essentially this is a workaround for the CloudStack getUsage() API call returning a corrupted
+    * form of ISO-8601 dates, which have an unexpected pair of apostrophes, like
+    * 2011-12-12'T'00:00:00+00:00
+    * 
+    * @author Richard Downer
+    */
+   public static class CloudStackDateAdapter extends Iso8601DateAdapter {
+
+      @Inject
+      private CloudStackDateAdapter(DateService dateService) {
+         super(dateService);
+      }
+
+      public Date read(JsonReader reader) throws IOException {
+         return parseDate(reader.nextString().replaceAll("'T'", "T"));
+      }
+
+   }
+
+   /**
+    * Handles types that were previously strings and now arrays (ex. tags)
+    * 
+    * @author Adrian Cole
+    */
+   public static class CommaDelimitedOKIgnoreNullIterableTypeAdapterFactory extends IgnoreNullIterableTypeAdapterFactory {
+
+      @Override
+      protected <E> TypeAdapter<Iterable<E>> newIterableAdapter(final TypeAdapter<E> elementAdapter) {
+         return new TypeAdapter<Iterable<E>>() {
+            public void write(JsonWriter out, Iterable<E> value) throws IOException {
+               out.beginArray();
+               for (E element : value) {
+                  elementAdapter.write(out, element);
+               }
+               out.endArray();
+            }
+
+            @SuppressWarnings("unchecked")
+            public Iterable<E> read(JsonReader in) throws IOException {
+               // HACK as cloudstack changed a field from String to Set!
+               if (in.peek() == JsonToken.STRING) {
+                  String val = Strings.emptyToNull(in.nextString());
+                  return (Iterable<E>) (val != null ? Splitter.on(',').split(val) : ImmutableSet.of());
+               } else {
+                  Builder<E> builder = ImmutableList.<E> builder();
+                  in.beginArray();
+                  while (in.hasNext()) {
+                     E element = elementAdapter.read(in);
+                     if (element != null)
+                        builder.add(element);
+                  }
+                  in.endArray();
+                  return builder.build();
+               }
+            }
+         }.nullSafe();
+      }
+   }
+
+}
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
index 695d728..cbdb216 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/config/CloudStackRestClientModule.java
@@ -33,7 +33,86 @@
 import org.jclouds.cloudstack.CloudStackGlobalAsyncClient;
 import org.jclouds.cloudstack.CloudStackGlobalClient;
 import org.jclouds.cloudstack.domain.LoginResponse;
-import org.jclouds.cloudstack.features.*;
+import org.jclouds.cloudstack.features.AccountAsyncClient;
+import org.jclouds.cloudstack.features.AccountClient;
+import org.jclouds.cloudstack.features.AddressAsyncClient;
+import org.jclouds.cloudstack.features.AddressClient;
+import org.jclouds.cloudstack.features.AsyncJobAsyncClient;
+import org.jclouds.cloudstack.features.AsyncJobClient;
+import org.jclouds.cloudstack.features.ConfigurationAsyncClient;
+import org.jclouds.cloudstack.features.ConfigurationClient;
+import org.jclouds.cloudstack.features.DomainAccountAsyncClient;
+import org.jclouds.cloudstack.features.DomainAccountClient;
+import org.jclouds.cloudstack.features.DomainDomainAsyncClient;
+import org.jclouds.cloudstack.features.DomainDomainClient;
+import org.jclouds.cloudstack.features.DomainLimitAsyncClient;
+import org.jclouds.cloudstack.features.DomainLimitClient;
+import org.jclouds.cloudstack.features.DomainUserAsyncClient;
+import org.jclouds.cloudstack.features.DomainUserClient;
+import org.jclouds.cloudstack.features.EventAsyncClient;
+import org.jclouds.cloudstack.features.EventClient;
+import org.jclouds.cloudstack.features.FirewallAsyncClient;
+import org.jclouds.cloudstack.features.FirewallClient;
+import org.jclouds.cloudstack.features.GlobalAccountAsyncClient;
+import org.jclouds.cloudstack.features.GlobalAccountClient;
+import org.jclouds.cloudstack.features.GlobalAlertAsyncClient;
+import org.jclouds.cloudstack.features.GlobalAlertClient;
+import org.jclouds.cloudstack.features.GlobalCapacityAsyncClient;
+import org.jclouds.cloudstack.features.GlobalCapacityClient;
+import org.jclouds.cloudstack.features.GlobalConfigurationAsyncClient;
+import org.jclouds.cloudstack.features.GlobalConfigurationClient;
+import org.jclouds.cloudstack.features.GlobalDomainAsyncClient;
+import org.jclouds.cloudstack.features.GlobalDomainClient;
+import org.jclouds.cloudstack.features.GlobalHostAsyncClient;
+import org.jclouds.cloudstack.features.GlobalHostClient;
+import org.jclouds.cloudstack.features.GlobalOfferingAsyncClient;
+import org.jclouds.cloudstack.features.GlobalOfferingClient;
+import org.jclouds.cloudstack.features.GlobalPodAsyncClient;
+import org.jclouds.cloudstack.features.GlobalPodClient;
+import org.jclouds.cloudstack.features.GlobalStoragePoolAsyncClient;
+import org.jclouds.cloudstack.features.GlobalStoragePoolClient;
+import org.jclouds.cloudstack.features.GlobalUsageAsyncClient;
+import org.jclouds.cloudstack.features.GlobalUsageClient;
+import org.jclouds.cloudstack.features.GlobalUserAsyncClient;
+import org.jclouds.cloudstack.features.GlobalUserClient;
+import org.jclouds.cloudstack.features.GlobalVlanAsyncClient;
+import org.jclouds.cloudstack.features.GlobalVlanClient;
+import org.jclouds.cloudstack.features.GlobalZoneAsyncClient;
+import org.jclouds.cloudstack.features.GlobalZoneClient;
+import org.jclouds.cloudstack.features.GuestOSAsyncClient;
+import org.jclouds.cloudstack.features.GuestOSClient;
+import org.jclouds.cloudstack.features.HypervisorAsyncClient;
+import org.jclouds.cloudstack.features.HypervisorClient;
+import org.jclouds.cloudstack.features.ISOAsyncClient;
+import org.jclouds.cloudstack.features.ISOClient;
+import org.jclouds.cloudstack.features.LimitAsyncClient;
+import org.jclouds.cloudstack.features.LimitClient;
+import org.jclouds.cloudstack.features.LoadBalancerAsyncClient;
+import org.jclouds.cloudstack.features.LoadBalancerClient;
+import org.jclouds.cloudstack.features.NATAsyncClient;
+import org.jclouds.cloudstack.features.NATClient;
+import org.jclouds.cloudstack.features.NetworkAsyncClient;
+import org.jclouds.cloudstack.features.NetworkClient;
+import org.jclouds.cloudstack.features.OfferingAsyncClient;
+import org.jclouds.cloudstack.features.OfferingClient;
+import org.jclouds.cloudstack.features.SSHKeyPairAsyncClient;
+import org.jclouds.cloudstack.features.SSHKeyPairClient;
+import org.jclouds.cloudstack.features.SecurityGroupAsyncClient;
+import org.jclouds.cloudstack.features.SecurityGroupClient;
+import org.jclouds.cloudstack.features.SessionAsyncClient;
+import org.jclouds.cloudstack.features.SessionClient;
+import org.jclouds.cloudstack.features.SnapshotAsyncClient;
+import org.jclouds.cloudstack.features.SnapshotClient;
+import org.jclouds.cloudstack.features.TemplateAsyncClient;
+import org.jclouds.cloudstack.features.TemplateClient;
+import org.jclouds.cloudstack.features.VMGroupAsyncClient;
+import org.jclouds.cloudstack.features.VMGroupClient;
+import org.jclouds.cloudstack.features.VirtualMachineAsyncClient;
+import org.jclouds.cloudstack.features.VirtualMachineClient;
+import org.jclouds.cloudstack.features.VolumeAsyncClient;
+import org.jclouds.cloudstack.features.VolumeClient;
+import org.jclouds.cloudstack.features.ZoneAsyncClient;
+import org.jclouds.cloudstack.features.ZoneClient;
 import org.jclouds.cloudstack.filters.AddSessionKeyAndJSessionIdToRequest;
 import org.jclouds.cloudstack.filters.AuthenticationFilter;
 import org.jclouds.cloudstack.filters.QuerySigner;
@@ -47,7 +126,6 @@
 import org.jclouds.http.annotation.ClientError;
 import org.jclouds.http.annotation.Redirection;
 import org.jclouds.http.annotation.ServerError;
-import org.jclouds.json.config.GsonModule.DateAdapter;
 import org.jclouds.location.Provider;
 import org.jclouds.location.suppliers.ImplicitLocationSupplier;
 import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstZone;
@@ -147,7 +225,6 @@
 
    @Override
    protected void configure() {
-      bind(DateAdapter.class).to(CloudStackDateAdapter.class);
       bind(new TypeLiteral<RestContext<CloudStackDomainClient, CloudStackDomainAsyncClient>>() {
       }).to(new TypeLiteral<RestContextImpl<CloudStackDomainClient, CloudStackDomainAsyncClient>>() {
       });
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/DiskOffering.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/DiskOffering.java
index ba0a587..97632e4 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/DiskOffering.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/DiskOffering.java
@@ -22,11 +22,13 @@
 
 import java.beans.ConstructorProperties;
 import java.util.Date;
+import java.util.Set;
 
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Class DiskOffering
@@ -54,7 +56,7 @@
       protected String domainId;
       protected int diskSize;
       protected boolean customized;
-      protected String tags;
+      protected ImmutableSet.Builder<String> tags = ImmutableSet.<String>builder();
 
       /**
        * @see DiskOffering#getId()
@@ -123,13 +125,21 @@
       /**
        * @see DiskOffering#getTags()
        */
-      public T tags(String tags) {
-         this.tags = tags;
+      public T tags(Iterable<String> tags) {
+         this.tags = ImmutableSet.<String>builder().addAll(tags);
          return self();
       }
-
+      
+      /**
+       * @see DiskOffering#getTags()
+       */
+      public T tag(String tag) {
+         this.tags.add(tag);
+         return self();
+      }
+      
       public DiskOffering build() {
-         return new DiskOffering(id, name, displayText, created, domain, domainId, diskSize, customized, tags);
+         return new DiskOffering(id, name, displayText, created, domain, domainId, diskSize, customized, tags.build());
       }
 
       public T fromDiskOffering(DiskOffering in) {
@@ -161,14 +171,14 @@
    private final String domainId;
    private final int diskSize;
    private final boolean customized;
-   private final String tags;
+   private final Set<String> tags;
 
    @ConstructorProperties({
          "id", "name", "displaytext", "created", "domain", "domainid", "disksize", "iscustomized", "tags"
    })
    protected DiskOffering(String id, @Nullable String name, @Nullable String displayText, @Nullable Date created,
                           @Nullable String domain, @Nullable String domainId, int diskSize, boolean customized,
-                          @Nullable String tags) {
+                          @Nullable Iterable<String> tags) {
       this.id = checkNotNull(id, "id");
       this.name = name;
       this.displayText = displayText;
@@ -177,7 +187,7 @@
       this.domainId = domainId;
       this.diskSize = diskSize;
       this.customized = customized;
-      this.tags = tags;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<String> of();
    }
 
    /**
@@ -244,8 +254,7 @@
    /**
     * @return the tags for the disk offering
     */
-   @Nullable
-   public String getTags() {
+   public Set<String> getTags() {
       return this.tags;
    }
 
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java
index 7d9ea4a..1cd4c6e 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Host.java
@@ -24,11 +24,13 @@
 
 import java.beans.ConstructorProperties;
 import java.util.Date;
+import java.util.Set;
 
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Represents a host issued by Cloudstack
@@ -149,7 +151,7 @@
       protected long diskSizeTotal;
       protected String events;
       protected boolean hasEnoughCapacity;
-      protected String hostTags;
+      protected ImmutableSet.Builder<String> tags = ImmutableSet.<String>builder();
       protected String hypervisor;
       protected String ipAddress;
       protected boolean localStorageActive;
@@ -319,13 +321,21 @@
       }
 
       /**
-       * @see Host#getHostTags()
+       * @see Host#getTags()
        */
-      public T hostTags(String hostTags) {
-         this.hostTags = hostTags;
+      public T tags(Iterable<String> tags) {
+         this.tags = ImmutableSet.<String>builder().addAll(tags);
          return self();
       }
-
+      
+      /**
+       * @see Host#getTags()
+       */
+      public T tag(String tag) {
+         this.tags.add(tag);
+         return self();
+      }
+      
       /**
        * @see Host#getHypervisor()
        */
@@ -512,7 +522,7 @@
 
 
       public Host build() {
-         return new Host(id, allocationState, averageLoad, capabilities, clusterId, clusterName, clusterType, cpuAllocated, cpuNumber, cpuSpeed, cpuUsed, cpuWithOverProvisioning, created, disconnected, diskSizeAllocated, diskSizeTotal, events, hasEnoughCapacity, hostTags, hypervisor, ipAddress, localStorageActive, jobId, jobStatus, lastPinged, managementServerId, memoryAllocated, memoryTotal, memoryUsed, name, networkKbsRead, networkKbsWrite, osCategoryId, osCategoryName, podId, podName, removed, state, type, version, zoneId, zoneName);
+         return new Host(id, allocationState, averageLoad, capabilities, clusterId, clusterName, clusterType, cpuAllocated, cpuNumber, cpuSpeed, cpuUsed, cpuWithOverProvisioning, created, disconnected, diskSizeAllocated, diskSizeTotal, events, hasEnoughCapacity, tags.build(), hypervisor, ipAddress, localStorageActive, jobId, jobStatus, lastPinged, managementServerId, memoryAllocated, memoryTotal, memoryUsed, name, networkKbsRead, networkKbsWrite, osCategoryId, osCategoryName, podId, podName, removed, state, type, version, zoneId, zoneName);
       }
 
       public T fromHost(Host in) {
@@ -535,7 +545,7 @@
                .diskSizeTotal(in.getDiskSizeTotal())
                .events(in.getEvents())
                .hasEnoughCapacity(in.isHasEnoughCapacity())
-               .hostTags(in.getHostTags())
+               .tags(in.getTags())
                .hypervisor(in.getHypervisor())
                .ipAddress(in.getIpAddress())
                .localStorageActive(in.isLocalStorageActive())
@@ -587,7 +597,7 @@
    private final long diskSizeTotal;
    private final String events;
    private final boolean hasEnoughCapacity;
-   private final String hostTags;
+   private final Set<String> tags;
    private final String hypervisor;
    private final String ipAddress;
    private final boolean localStorageActive;
@@ -619,7 +629,7 @@
                   @Nullable String clusterId, @Nullable String clusterName, @Nullable Host.ClusterType clusterType,
                   @Nullable String cpuAllocated, int cpuNumber, int cpuSpeed, @Nullable String cpuUsed,
                   float cpuWithOverProvisioning, @Nullable Date created, @Nullable Date disconnected, long diskSizeAllocated,
-                  long diskSizeTotal, @Nullable String events, boolean hasEnoughCapacity, @Nullable String hostTags,
+                  long diskSizeTotal, @Nullable String events, boolean hasEnoughCapacity, @Nullable Iterable<String> tags,
                   @Nullable String hypervisor, @Nullable String ipAddress, boolean localStorageActive, @Nullable String jobId,
                   @Nullable AsyncJob.Status jobStatus, @Nullable Date lastPinged, @Nullable String managementServerId,
                   long memoryAllocated, long memoryTotal, long memoryUsed, @Nullable String name, long networkKbsRead, long networkKbsWrite,
@@ -644,7 +654,7 @@
       this.diskSizeTotal = diskSizeTotal;
       this.events = events;
       this.hasEnoughCapacity = hasEnoughCapacity;
-      this.hostTags = hostTags;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<String> of();
       this.hypervisor = hypervisor;
       this.ipAddress = ipAddress;
       this.localStorageActive = localStorageActive;
@@ -752,11 +762,14 @@
       return this.hasEnoughCapacity;
    }
 
-   @Nullable
-   public String getHostTags() {
-      return this.hostTags;
+   /**
+    * @return the tags for the host
+    */
+   public Set<String> getTags() {
+      return this.tags;
    }
 
+
    @Nullable
    public String getHypervisor() {
       return this.hypervisor;
@@ -868,7 +881,7 @@
 
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, allocationState, averageLoad, capabilities, clusterId, clusterName, clusterType, cpuAllocated, cpuNumber, cpuSpeed, cpuUsed, cpuWithOverProvisioning, created, disconnected, diskSizeAllocated, diskSizeTotal, events, hasEnoughCapacity, hostTags, hypervisor, ipAddress, localStorageActive, jobId, jobStatus, lastPinged, managementServerId, memoryAllocated, memoryTotal, memoryUsed, name, networkKbsRead, networkKbsWrite, osCategoryId, osCategoryName, podId, podName, removed, state, type, version, zoneId, zoneName);
+      return Objects.hashCode(id, allocationState, averageLoad, capabilities, clusterId, clusterName, clusterType, cpuAllocated, cpuNumber, cpuSpeed, cpuUsed, cpuWithOverProvisioning, created, disconnected, diskSizeAllocated, diskSizeTotal, events, hasEnoughCapacity, tags, hypervisor, ipAddress, localStorageActive, jobId, jobStatus, lastPinged, managementServerId, memoryAllocated, memoryTotal, memoryUsed, name, networkKbsRead, networkKbsWrite, osCategoryId, osCategoryName, podId, podName, removed, state, type, version, zoneId, zoneName);
    }
 
    @Override
@@ -894,7 +907,7 @@
             && Objects.equal(this.diskSizeTotal, that.diskSizeTotal)
             && Objects.equal(this.events, that.events)
             && Objects.equal(this.hasEnoughCapacity, that.hasEnoughCapacity)
-            && Objects.equal(this.hostTags, that.hostTags)
+            && Objects.equal(this.tags, that.tags)
             && Objects.equal(this.hypervisor, that.hypervisor)
             && Objects.equal(this.ipAddress, that.ipAddress)
             && Objects.equal(this.localStorageActive, that.localStorageActive)
@@ -928,7 +941,7 @@
             .add("cpuSpeed", cpuSpeed).add("cpuUsed", cpuUsed).add("cpuWithOverProvisioning", cpuWithOverProvisioning)
             .add("created", created).add("disconnected", disconnected).add("diskSizeAllocated", diskSizeAllocated)
             .add("diskSizeTotal", diskSizeTotal).add("events", events).add("hasEnoughCapacity", hasEnoughCapacity)
-            .add("hostTags", hostTags).add("hypervisor", hypervisor).add("ipAddress", ipAddress)
+            .add("tags", tags).add("hypervisor", hypervisor).add("ipAddress", ipAddress)
             .add("localStorageActive", localStorageActive).add("jobId", jobId).add("jobStatus", jobStatus)
             .add("lastPinged", lastPinged).add("managementServerId", managementServerId).add("memoryAllocated", memoryAllocated)
             .add("memoryTotal", memoryTotal).add("memoryUsed", memoryUsed).add("name", name).add("networkKbsRead", networkKbsRead)
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java
index 457edd0..08dd450 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/Network.java
@@ -30,6 +30,7 @@
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 
 /**
@@ -78,7 +79,7 @@
       protected String VLAN;
       protected TrafficType trafficType;
       protected String zoneId;
-      protected String tags;
+      protected ImmutableSet.Builder<String> tags = ImmutableSet.<String>builder();
       protected boolean securityGroupEnabled;
       protected Set<? extends NetworkService> services = ImmutableSortedSet.of();
 
@@ -302,10 +303,19 @@
       /**
        * @see Network#getTags()
        */
-      public T tags(String tags) {
-         this.tags = tags;
+      public T tags(Iterable<String> tags) {
+         this.tags = ImmutableSet.<String>builder().addAll(tags);
          return self();
       }
+      
+      /**
+       * @see Network#getTags()
+       */
+      public T tag(String tag) {
+         this.tags.add(tag);
+         return self();
+      }
+      
 
       /**
        * @see Network#isSecurityGroupEnabled()
@@ -324,7 +334,7 @@
       }
 
       public Network build() {
-         return new Network(id, account, broadcastDomainType, broadcastURI, displayText, DNS1, DNS2, domain, domainId, endIP, gateway, isDefault, isShared, isSystem, netmask, networkDomain, networkOfferingAvailability, networkOfferingDisplayText, networkOfferingId, networkOfferingName, related, startIP, name, state, guestIPType, VLAN, trafficType, zoneId, tags, securityGroupEnabled, services);
+         return new Network(id, account, broadcastDomainType, broadcastURI, displayText, DNS1, DNS2, domain, domainId, endIP, gateway, isDefault, isShared, isSystem, netmask, networkDomain, networkOfferingAvailability, networkOfferingDisplayText, networkOfferingId, networkOfferingName, related, startIP, name, state, guestIPType, VLAN, trafficType, zoneId, tags.build(), securityGroupEnabled, services);
       }
 
       public T fromNetwork(Network in) {
@@ -397,7 +407,7 @@
    private final String VLAN;
    private final TrafficType trafficType;
    private final String zoneId;
-   private final String tags;
+   private final Set<String> tags;
    private final boolean securityGroupEnabled;
    private final Set<? extends NetworkService> services;
 
@@ -411,7 +421,7 @@
                      @Nullable String networkOfferingDisplayText, @Nullable String networkOfferingId, @Nullable String networkOfferingName,
                      @Nullable String related, @Nullable String startIP, @Nullable String name, @Nullable String state,
                      @Nullable GuestIPType guestIPType, @Nullable String VLAN, @Nullable TrafficType trafficType,
-                     @Nullable String zoneId, @Nullable String tags, boolean securityGroupEnabled, Set<? extends NetworkService> services) {
+                     @Nullable String zoneId, @Nullable Iterable<String> tags, boolean securityGroupEnabled, Set<? extends NetworkService> services) {
       this.id = checkNotNull(id, "id");
       this.account = account;
       this.broadcastDomainType = broadcastDomainType;
@@ -440,7 +450,7 @@
       this.VLAN = VLAN;
       this.trafficType = trafficType;
       this.zoneId = zoneId;
-      this.tags = tags;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<String> of();
       this.securityGroupEnabled = securityGroupEnabled;
       this.services = ImmutableSortedSet.copyOf(services);
    }
@@ -660,8 +670,7 @@
    /**
     * @return the tags for the Network
     */
-   @Nullable
-   public String getTags() {
+   public Set<String> getTags() {
       return this.tags;
    }
 
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/NetworkOffering.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/NetworkOffering.java
index 876b524..1ec0a85 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/NetworkOffering.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/NetworkOffering.java
@@ -22,11 +22,13 @@
 
 import java.beans.ConstructorProperties;
 import java.util.Date;
+import java.util.Set;
 
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Class NetworkOffering
@@ -57,7 +59,7 @@
       protected TrafficType trafficType;
       protected GuestIPType guestIPType;
       protected int networkRate;
-      protected String tags;
+      protected ImmutableSet.Builder<String> tags = ImmutableSet.<String>builder();
 
       /**
        * @see NetworkOffering#getId()
@@ -146,17 +148,26 @@
          this.networkRate = networkRate;
          return self();
       }
-
+      
       /**
        * @see NetworkOffering#getTags()
        */
-      public T tags(String tags) {
-         this.tags = tags;
+      public T tags(Iterable<String> tags) {
+         this.tags = ImmutableSet.<String>builder().addAll(tags);
          return self();
       }
+      
+      /**
+       * @see NetworkOffering#getTags()
+       */
+      public T tag(String tag) {
+         this.tags.add(tag);
+         return self();
+      }
+      
 
       public NetworkOffering build() {
-         return new NetworkOffering(id, name, displayText, created, availability, maxConnections, isDefault, supportsVLAN, trafficType, guestIPType, networkRate, tags);
+         return new NetworkOffering(id, name, displayText, created, availability, maxConnections, isDefault, supportsVLAN, trafficType, guestIPType, networkRate, tags.build());
       }
 
       public T fromNetworkOffering(NetworkOffering in) {
@@ -194,12 +205,12 @@
    private final TrafficType trafficType;
    private final GuestIPType guestIPType;
    private final int networkRate;
-   private final String tags;
+   private final Set<String> tags;
 
    @ConstructorProperties({
          "id", "name", "displaytext", "created", "availability", "maxconnections", "isdefault", "specifyvlan", "traffictype", "guestiptype", "networkrate", "tags"
    })
-   protected NetworkOffering(String id, @Nullable String name, @Nullable String displayText, @Nullable Date created, @Nullable NetworkOfferingAvailabilityType availability, @Nullable Integer maxConnections, boolean isDefault, boolean supportsVLAN, @Nullable TrafficType trafficType, @Nullable GuestIPType guestIPType, int networkRate, @Nullable String tags) {
+   protected NetworkOffering(String id, @Nullable String name, @Nullable String displayText, @Nullable Date created, @Nullable NetworkOfferingAvailabilityType availability, @Nullable Integer maxConnections, boolean isDefault, boolean supportsVLAN, @Nullable TrafficType trafficType, @Nullable GuestIPType guestIPType, int networkRate, @Nullable Iterable<String> tags) {
       this.id = checkNotNull(id, "id");
       this.name = name;
       this.displayText = displayText;
@@ -211,7 +222,7 @@
       this.trafficType = trafficType;
       this.guestIPType = guestIPType;
       this.networkRate = networkRate;
-      this.tags = tags;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<String> of();
    }
 
    /**
@@ -302,8 +313,7 @@
    /**
     * @return the tags for the network offering
     */
-   @Nullable
-   public String getTags() {
+   public Set<String> getTags() {
       return this.tags;
    }
 
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ServiceOffering.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ServiceOffering.java
index b5bd47f..e472da7 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ServiceOffering.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/ServiceOffering.java
@@ -26,11 +26,8 @@
 
 import org.jclouds.javax.annotation.Nullable;
 
-import com.google.common.base.Joiner;
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -63,12 +60,11 @@
       protected boolean haSupport;
       protected StorageType storageType;
       protected boolean defaultUse;
-      protected String hostTags;
       protected boolean systemOffering;
       protected boolean cpuUseLimited;
       protected long networkRate;
       protected boolean systemVmType;
-      private Set<String> tags = ImmutableSet.of();
+      protected ImmutableSet.Builder<String> tags = ImmutableSet.<String>builder();
 
       /**
        * @see ServiceOffering#getId()
@@ -161,11 +157,19 @@
       /**
        * @see ServiceOffering#getTags()
        */
-      public T tags(Set<String> tags) {
-         this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
+      public T tags(Iterable<String> tags) {
+         this.tags = ImmutableSet.<String>builder().addAll(tags);
          return self();
       }
-
+      
+      /**
+       * @see ServiceOffering#getTags()
+       */
+      public T tag(String tag) {
+         this.tags.add(tag);
+         return self();
+      }
+      
       /**
        * @see ServiceOffering#isDefaultUse()
        */
@@ -175,14 +179,6 @@
       }
 
       /**
-       * @see ServiceOffering#getHostTags()
-       */
-      public T hostTags(String hostTags) {
-         this.hostTags = hostTags;
-         return self();
-      }
-
-      /**
        * @see ServiceOffering#isSystemOffering()
        */
       public T systemOffering(boolean systemOffering) {
@@ -216,7 +212,7 @@
 
       public ServiceOffering build() {
          return new ServiceOffering(id, name, displayText, created, domain, domainId, cpuNumber, cpuSpeed, memory, haSupport, storageType,
-               Joiner.on(",").join(tags), defaultUse, hostTags, systemOffering, cpuUseLimited, networkRate, systemVmType);
+               tags.build(), defaultUse, systemOffering, cpuUseLimited, networkRate, systemVmType);
       }
 
       public T fromServiceOffering(ServiceOffering in) {
@@ -234,7 +230,6 @@
                .storageType(in.getStorageType())
                .tags(in.getTags())
                .defaultUse(in.isDefaultUse())
-               .hostTags(in.getHostTags())
                .systemOffering(in.isSystemOffering())
                .cpuUseLimited(in.isCpuUseLimited())
                .networkRate(in.getNetworkRate())
@@ -262,19 +257,18 @@
    private final StorageType storageType;
    private final Set<String> tags;
    private final boolean defaultUse;
-   private final String hostTags;
    private final boolean systemOffering;
    private final boolean cpuUseLimited;
    private final long networkRate;
    private final boolean systemVmType;
 
    @ConstructorProperties({
-         "id", "name", "displaytext", "created", "domain", "domainid", "cpunumber", "cpuspeed", "memory", "offerha", "storagetype", "tags", "defaultuse", "hosttags", "issystem", "limitcpuuse", "networkrate", "systemvmtype"
+         "id", "name", "displaytext", "created", "domain", "domainid", "cpunumber", "cpuspeed", "memory", "offerha", "storagetype", "tags", "defaultuse", "issystem", "limitcpuuse", "networkrate", "systemvmtype"
    })
    protected ServiceOffering(String id, @Nullable String name, @Nullable String displayText, @Nullable Date created,
                              @Nullable String domain, @Nullable String domainId, int cpuNumber, int cpuSpeed, int memory,
-                             boolean haSupport, @Nullable StorageType storageType, @Nullable String tags, boolean defaultUse,
-                             @Nullable String hostTags, boolean systemOffering, boolean cpuUseLimited, long networkRate, boolean systemVmType) {
+                             boolean haSupport, @Nullable StorageType storageType, @Nullable Iterable<String> tags, boolean defaultUse,
+                             boolean systemOffering, boolean cpuUseLimited, long networkRate, boolean systemVmType) {
       this.id = checkNotNull(id, "id");
       this.name = name;
       this.displayText = displayText;
@@ -286,10 +280,8 @@
       this.memory = memory;
       this.haSupport = haSupport;
       this.storageType = storageType;
-      this.tags = !(Strings.emptyToNull(tags) == null) ? ImmutableSet.copyOf(Splitter.on(',').split(tags))
-               : ImmutableSet.<String> of();
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<String> of();
       this.defaultUse = defaultUse;
-      this.hostTags = hostTags;
       this.systemOffering = systemOffering;
       this.cpuUseLimited = cpuUseLimited;
       this.networkRate = networkRate;
@@ -390,14 +382,6 @@
    }
 
    /**
-    * @return the host tag for the service offering
-    */
-   @Nullable
-   public String getHostTags() {
-      return this.hostTags;
-   }
-
-   /**
     * @return whether this is a system vm offering
     */
    public boolean isSystemOffering() {
@@ -427,7 +411,7 @@
 
    @Override
    public int hashCode() {
-      return Objects.hashCode(id, name, displayText, created, domain, domainId, cpuNumber, cpuSpeed, memory, haSupport, storageType, tags, defaultUse, hostTags, systemOffering, cpuUseLimited, networkRate, systemVmType);
+      return Objects.hashCode(id, name, displayText, created, domain, domainId, cpuNumber, cpuSpeed, memory, haSupport, storageType, tags, defaultUse, systemOffering, cpuUseLimited, networkRate, systemVmType);
    }
 
    @Override
@@ -448,7 +432,6 @@
             && Objects.equal(this.storageType, that.storageType)
             && Objects.equal(this.getTags(), that.getTags())
             && Objects.equal(this.defaultUse, that.defaultUse)
-            && Objects.equal(this.hostTags, that.hostTags)
             && Objects.equal(this.systemOffering, that.systemOffering)
             && Objects.equal(this.cpuUseLimited, that.cpuUseLimited)
             && Objects.equal(this.networkRate, that.networkRate)
@@ -460,7 +443,7 @@
             .add("id", id).add("name", name).add("displayText", displayText).add("created", created).add("domain", domain)
             .add("domainId", domainId).add("cpuNumber", cpuNumber).add("cpuSpeed", cpuSpeed).add("memory", memory)
             .add("haSupport", haSupport).add("storageType", storageType).add("tags", getTags()).add("defaultUse", defaultUse)
-            .add("hostTags", hostTags).add("systemOffering", systemOffering).add("cpuUseLimited", cpuUseLimited)
+            .add("systemOffering", systemOffering).add("cpuUseLimited", cpuUseLimited)
             .add("networkRate", networkRate).add("systemVmType", systemVmType);
    }
 
diff --git a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/StoragePool.java b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/StoragePool.java
index 5416c07..5c9a327 100644
--- a/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/StoragePool.java
+++ b/apis/cloudstack/src/main/java/org/jclouds/cloudstack/domain/StoragePool.java
@@ -22,12 +22,14 @@
 
 import java.beans.ConstructorProperties;
 import java.util.Date;
+import java.util.Set;
 
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.CaseFormat;
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Represents a storage pool in CloudStack
@@ -102,7 +104,7 @@
       protected String id;
       protected String name;
       protected String path;
-      protected String tags;
+      protected ImmutableSet.Builder<String> tags = ImmutableSet.<String>builder();
       protected StoragePool.State state;
       protected StoragePool.Type type;
       protected String zoneId;
@@ -143,10 +145,18 @@
       }
 
       /**
-       * @see StoragePool#getTags()
+       * @see DiskOffering#getTags()
        */
-      public T tags(String tags) {
-         this.tags = tags;
+      public T tags(Iterable<String> tags) {
+         this.tags = ImmutableSet.<String>builder().addAll(tags);
+         return self();
+      }
+      
+      /**
+       * @see DiskOffering#getTags()
+       */
+      public T tag(String tag) {
+         this.tags.add(tag);
          return self();
       }
 
@@ -263,7 +273,7 @@
       }
 
       public StoragePool build() {
-         return new StoragePool(id, name, path, tags, state, type, zoneId, zoneName, podId, podName, clusterId, clusterName, created, diskSizeAllocated, diskSizeTotal, ipAddress, jobId, jobStatus);
+         return new StoragePool(id, name, path, tags.build(), state, type, zoneId, zoneName, podId, podName, clusterId, clusterName, created, diskSizeAllocated, diskSizeTotal, ipAddress, jobId, jobStatus);
       }
 
       public T fromStoragePool(StoragePool in) {
@@ -299,7 +309,7 @@
    private final String id;
    private final String name;
    private final String path;
-   private final String tags;
+   private final Set<String> tags;
    private final StoragePool.State state;
    private final StoragePool.Type type;
    private final String zoneId;
@@ -318,11 +328,15 @@
    @ConstructorProperties({
          "id", "name", "path", "tags", "state", "type", "zoneid", "zonename", "podid", "podname", "clusterid", "clustername", "created", "disksizeallocated", "disksizetotal", "ipaddress", "jobid", "jobstatus"
    })
-   protected StoragePool(String id, @Nullable String name, @Nullable String path, @Nullable String tags, @Nullable StoragePool.State state, @Nullable StoragePool.Type type, @Nullable String zoneId, @Nullable String zoneName, @Nullable String podId, @Nullable String podName, @Nullable String clusterId, @Nullable String clusterName, @Nullable Date created, long diskSizeAllocated, long diskSizeTotal, @Nullable String ipAddress, @Nullable String jobId, @Nullable String jobStatus) {
+   protected StoragePool(String id, @Nullable String name, @Nullable String path, @Nullable Iterable<String> tags,
+            @Nullable StoragePool.State state, @Nullable StoragePool.Type type, @Nullable String zoneId,
+            @Nullable String zoneName, @Nullable String podId, @Nullable String podName, @Nullable String clusterId,
+            @Nullable String clusterName, @Nullable Date created, long diskSizeAllocated, long diskSizeTotal,
+            @Nullable String ipAddress, @Nullable String jobId, @Nullable String jobStatus) {
       this.id = checkNotNull(id, "id");
       this.name = name;
       this.path = path;
-      this.tags = tags;
+      this.tags = tags != null ? ImmutableSet.copyOf(tags) : ImmutableSet.<String> of();
       this.state = state;
       this.type = type;
       this.zoneId = zoneId;
@@ -353,8 +367,7 @@
       return this.path;
    }
 
-   @Nullable
-   public String getTags() {
+   public Set<String> getTags() {
       return this.tags;
    }
 
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java
index 26c96b0..1f17abd 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/features/GlobalHostClientExpectTest.java
@@ -65,7 +65,7 @@
 
       Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "GMT+02:00");
       Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "GMT+02:00");
-      Host host1 = Host.builder().id("1").name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId("1").zoneName("Dev Zone 1").podId("1").podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId("223098941760041").clusterId("1").clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(AllocationState.ENABLED).build();
+      Host host1 = Host.builder().id("1").name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId("1").zoneName("Dev Zone 1").podId("1").podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId("223098941760041").clusterId("1").clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hasEnoughCapacity(false).allocationState(AllocationState.ENABLED).build();
 
       Date disconnected = makeDate(2011, Calendar.NOVEMBER, 26, 23, 33, 38, "GMT+02:00");
       lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 42, 30, "GMT+02:00");
@@ -109,7 +109,7 @@
 
       Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "GMT+02:00");
       Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "GMT+02:00");
-      Host expected = Host.builder().id("1").name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId("1").zoneName("Dev Zone 1").podId("1").podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId("223098941760041").clusterId("1").clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(AllocationState.ENABLED).build();
+      Host expected = Host.builder().id("1").name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId("1").zoneName("Dev Zone 1").podId("1").podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId("223098941760041").clusterId("1").clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hasEnoughCapacity(false).allocationState(AllocationState.ENABLED).build();
 
       Host actual = requestSendsResponse(request, response).addHost("1", "http://example.com", "XenServer", "fred", "sekrit",
          AddHostOptions.Builder.hostTags(Collections.<String>emptySet()).allocationState(AllocationState.ENABLED).clusterId("1").clusterName("Xen Clust 1").podId("1"));
@@ -129,7 +129,7 @@
 
       Date lastPinged = makeDate(1970, Calendar.JANUARY, 16, 0, 54, 43, "GMT+02:00");
       Date created = makeDate(2011, Calendar.NOVEMBER, 26, 23, 28, 36, "GMT+02:00");
-      Host expected = Host.builder().id("1").name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId("1").zoneName("Dev Zone 1").podId("1").podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId("223098941760041").clusterId("1").clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hostTags("").hasEnoughCapacity(false).allocationState(AllocationState.ENABLED).build();
+      Host expected = Host.builder().id("1").name("cs2-xevsrv.alucloud.local").state(Host.State.UP).type(Host.Type.ROUTING).ipAddress("10.26.26.107").zoneId("1").zoneName("Dev Zone 1").podId("1").podName("Dev Pod 1").version("2.2.12.20110928142833").hypervisor("XenServer").cpuNumber(24).cpuSpeed(2266).cpuAllocated("2.76%").cpuUsed("0.1%").cpuWithOverProvisioning(54384.0F).networkKbsRead(4443).networkKbsWrite(15048).memoryTotal(100549733760L).memoryAllocated(3623878656L).memoryUsed(3623878656L).capabilities("xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64").lastPinged(lastPinged).managementServerId("223098941760041").clusterId("1").clusterName("Xen Clust 1").clusterType(Host.ClusterType.CLOUD_MANAGED).localStorageActive(false).created(created).events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping").hasEnoughCapacity(false).allocationState(AllocationState.ENABLED).build();
 
       Host actual = requestSendsResponse(request, response).updateHost("1", UpdateHostOptions.Builder.allocationState(AllocationState.ENABLED).hostTags(Collections.<String>emptySet()).osCategoryId("5"));
 
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListHostsResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListHostsResponseTest.java
index b857fd6..60f9096 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListHostsResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListHostsResponseTest.java
@@ -22,17 +22,16 @@
 
 import java.util.Set;
 
+import org.jclouds.cloudstack.config.CloudStackParserModule;
 import org.jclouds.cloudstack.domain.AllocationState;
 import org.jclouds.cloudstack.domain.Host;
 import org.jclouds.date.internal.SimpleDateFormatDateService;
 import org.jclouds.json.BaseParserTest;
-import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.json.config.GsonModule;
 import org.jclouds.rest.annotations.SelectJson;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
@@ -48,16 +47,7 @@
 
    @Override
    protected Injector injector() {
-      return Guice.createInjector(new GsonModule() {
-
-         @Override
-         protected void configure() {
-            bind(DateAdapter.class).to(Iso8601DateAdapter.class);
-            super.configure();
-         }
-
-      });
-
+      return Guice.createInjector(new GsonModule(), new CloudStackParserModule());
    }
 
    @Override
@@ -102,7 +92,6 @@
             .created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2011-11-26T23:28:36+0200"))
             .events("PrepareUnmanaged; HypervisorVersionChanged; ManagementServerDown; PingTimeout; " +
                "AgentDisconnected; MaintenanceRequested; HostDown; AgentConnected; StartAgentRebalance; ShutdownRequested; Ping")
-            .hostTags("")
             .hasEnoughCapacity(false)
             .allocationState(AllocationState.ENABLED).build(),
 
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListStoragePoolsResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListStoragePoolsResponseTest.java
index 2c4f85d..661afca 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListStoragePoolsResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListStoragePoolsResponseTest.java
@@ -23,18 +23,22 @@
 import java.util.Set;
 import java.util.TimeZone;
 
+import org.jclouds.cloudstack.config.CloudStackParserModule;
 import org.jclouds.cloudstack.domain.StoragePool;
 import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
 import org.jclouds.rest.annotations.SelectJson;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
 
 /**
  * 
  * @author Richard Downer
  */
-@Test(groups = "unit")
+@Test(groups = "unit", testName = "ListStoragePoolsResponseTest")
 public class ListStoragePoolsResponseTest extends BaseItemParserTest<Set<StoragePool>> {
 
    @Override
@@ -54,7 +58,16 @@
       c.set(Calendar.SECOND, 6);
       Date created = c.getTime();
 
-      StoragePool storagePool = StoragePool.builder().id("201").zoneId("1").zoneName("Dev Zone 1").podId("1").podName("Dev Pod 1").name("NFS Pri 1").ipAddress("10.26.26.165").path("/mnt/nfs/cs_pri").created(created).type(StoragePool.Type.NETWORK_FILESYSTEM).clusterId("1").clusterName("Xen Clust 1").diskSizeTotal(898356445184L).diskSizeAllocated(18276679680L).tags("").state(StoragePool.State.UP).build();
+      StoragePool storagePool = StoragePool.builder().id("201").zoneId("1").zoneName("Dev Zone 1").podId("1")
+               .podName("Dev Pod 1").name("NFS Pri 1").ipAddress("10.26.26.165").path("/mnt/nfs/cs_pri")
+               .created(created).type(StoragePool.Type.NETWORK_FILESYSTEM).clusterId("1").clusterName("Xen Clust 1")
+               .diskSizeTotal(898356445184L).diskSizeAllocated(18276679680L).tag("tag1").state(StoragePool.State.UP)
+               .build();
       return ImmutableSet.of(storagePool);
    }
+   
+   @Override
+   protected Injector injector() {
+      return Guice.createInjector(new GsonModule(), new CloudStackParserModule());
+   }
 }
diff --git a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListUsageRecordsResponseTest.java b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListUsageRecordsResponseTest.java
index f88a1be..bc8e5db 100644
--- a/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListUsageRecordsResponseTest.java
+++ b/apis/cloudstack/src/test/java/org/jclouds/cloudstack/parse/ListUsageRecordsResponseTest.java
@@ -23,7 +23,7 @@
 import java.util.Set;
 import java.util.TimeZone;
 
-import org.jclouds.cloudstack.config.CloudStackDateAdapter;
+import org.jclouds.cloudstack.config.CloudStackParserModule;
 import org.jclouds.cloudstack.domain.UsageRecord;
 import org.jclouds.json.BaseSetParserTest;
 import org.jclouds.json.config.GsonModule;
@@ -69,17 +69,10 @@
             .templateId("0").id("203").startDate(start).endDate(end).build());
 
    }
-
+   
    @Override
    protected Injector injector() {
-      return Guice.createInjector(new GsonModule() {
-
-               @Override
-               protected void configure() {
-                  bind(DateAdapter.class).to(CloudStackDateAdapter.class);
-                  super.configure();
-               }
-
-            });
+      return Guice.createInjector(new GsonModule(), new CloudStackParserModule());
    }
+
 }
diff --git a/apis/cloudstack/src/test/resources/liststoragepoolsresponse.json b/apis/cloudstack/src/test/resources/liststoragepoolsresponse.json
index deca7a2..dc3ae46 100644
--- a/apis/cloudstack/src/test/resources/liststoragepoolsresponse.json
+++ b/apis/cloudstack/src/test/resources/liststoragepoolsresponse.json
@@ -1 +1 @@
-{ "liststoragepoolsresponse" : { "count":1 ,"storagepool" : [  {"id":201,"zoneid":1,"zonename":"Dev Zone 1","podid":1,"podname":"Dev Pod 1","name":"NFS Pri 1","ipaddress":"10.26.26.165","path":"/mnt/nfs/cs_pri","created":"2011-11-26T23:33:06+0200","type":"NetworkFilesystem","clusterid":1,"clustername":"Xen Clust 1","disksizetotal":898356445184,"disksizeallocated":18276679680,"tags":"","state":"Up"} ] } }
\ No newline at end of file
+{ "liststoragepoolsresponse" : { "count":1 ,"storagepool" : [  {"id":201,"zoneid":1,"zonename":"Dev Zone 1","podid":1,"podname":"Dev Pod 1","name":"NFS Pri 1","ipaddress":"10.26.26.165","path":"/mnt/nfs/cs_pri","created":"2011-11-26T23:33:06+0200","type":"NetworkFilesystem","clusterid":1,"clustername":"Xen Clust 1","disksizetotal":898356445184,"disksizeallocated":18276679680,"tags":"tag1","state":"Up"} ] } }
\ No newline at end of file
diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/binders/MetricDataBinder.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/binders/MetricDataBinder.java
index 997f437..3852418 100644
--- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/binders/MetricDataBinder.java
+++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/binders/MetricDataBinder.java
@@ -93,8 +93,10 @@
          formParameters.put("MetricData.member." + metricDatumIndex + ".Unit",
                             String.valueOf(metricDatum.getUnit()));
 
-         formParameters.put("MetricData.member." + metricDatumIndex + ".Value",
-                            String.valueOf(metricDatum.getValue()));
+         if (metricDatum.getValue().isPresent()) {
+            formParameters.put("MetricData.member." + metricDatumIndex + ".Value",
+                     String.valueOf(metricDatum.getValue().get()));
+         }
 
          metricDatumIndex++;
       }
diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/GetMetricStatisticsResponse.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/GetMetricStatisticsResponse.java
index 146de9c..d455908 100644
--- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/GetMetricStatisticsResponse.java
+++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/GetMetricStatisticsResponse.java
@@ -18,12 +18,12 @@
  */
 package org.jclouds.cloudwatch.domain;
 
-import java.util.Set;
+import java.util.Iterator;
 
 import org.jclouds.javax.annotation.Nullable;
 
 import com.google.common.base.Objects;
-import com.google.common.collect.ForwardingSet;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -33,12 +33,12 @@
  *
  * @author Jeremy Whitlock
  */
-public class GetMetricStatisticsResponse extends ForwardingSet<Datapoint> {
+public class GetMetricStatisticsResponse extends FluentIterable<Datapoint> {
 
-   private final Set<Datapoint> datapoints;
+   private final Iterable<Datapoint> datapoints;
    private final String label;
 
-   public GetMetricStatisticsResponse(@Nullable Set<Datapoint> datapoints, String label) {
+   public GetMetricStatisticsResponse(@Nullable Iterable<Datapoint> datapoints, String label) {
       // Default to an empty set
       if (datapoints == null) {
          this.datapoints = ImmutableSet.<Datapoint>of();
@@ -90,8 +90,8 @@
    }
 
    @Override
-   protected Set<Datapoint> delegate() {
-      return datapoints;
+   public Iterator<Datapoint> iterator() {
+      return datapoints.iterator();
    }
 
 }
diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/MetricDatum.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/MetricDatum.java
index 2bd2d13..23745a9 100644
--- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/MetricDatum.java
+++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/domain/MetricDatum.java
@@ -25,14 +25,16 @@
 import java.util.Set;
 
 import com.google.common.base.Objects;
-import com.google.common.base.Optional;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
 
 /**
- * @see <a href="http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html" />
- *
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/API_MetricDatum.html"
+ *      />
+ * 
  * @author Jeremy Whitlock
  */
 public class MetricDatum {
@@ -42,17 +44,17 @@
    private final Optional<StatisticValues> statisticValues;
    private final Optional<Date> timestamp;
    private final Unit unit;
-   private final double value;
+   private final Optional<Double> value;
 
    /**
     * Private constructor to enforce using {@link Builder}.
     */
-   protected MetricDatum(Set<Dimension> dimensions, String metricName, StatisticValues statisticValues, Date timestamp,
-                       Unit unit, double value) {
-      this.dimensions = ImmutableSet.<Dimension>copyOf(checkNotNull(dimensions, "dimensions"));
+   protected MetricDatum(Iterable<Dimension> dimensions, String metricName, Optional<StatisticValues> statisticValues,
+            Optional<Date> timestamp, Unit unit, Optional<Double> value) {
+      this.dimensions = ImmutableSet.<Dimension> copyOf(checkNotNull(dimensions, "dimensions"));
       this.metricName = checkNotNull(metricName, "metricName");
-      this.statisticValues = Optional.fromNullable(statisticValues);
-      this.timestamp = Optional.fromNullable(timestamp);
+      this.statisticValues = checkNotNull(statisticValues, "statisticValues");
+      this.timestamp = checkNotNull(timestamp, "timestamp");
       this.unit = checkNotNull(unit, "unit");
       this.value = checkNotNull(value, "value");
    }
@@ -95,13 +97,13 @@
    /**
     * return the actual value of the metric
     */
-   public double getValue() {
+   public Optional<Double> getValue() {
       return value;
    }
 
    /**
-    * Returns a new builder. The generated builder is equivalent to the builder
-    * created by the {@link Builder} constructor.
+    * Returns a new builder. The generated builder is equivalent to the builder created by the
+    * {@link Builder} constructor.
     */
    public static Builder builder() {
       return new Builder();
@@ -110,36 +112,39 @@
    public static class Builder {
 
       // this builder is set to be additive on dimension calls, so make this mutable
-      private Set<Dimension> dimensions = Sets.newLinkedHashSet();
+      private ImmutableList.Builder<Dimension> dimensions = ImmutableList.<Dimension> builder();
       private String metricName;
-      private StatisticValues statisticValues;
-      private Date timestamp;
+      private Optional<StatisticValues> statisticValues = Optional.absent();
+      private Optional<Date> timestamp = Optional.absent();
       private Unit unit = Unit.NONE;
-      private double value;
+      private Optional<Double> value = Optional.absent();
 
       /**
-       * Creates a new builder. The returned builder is equivalent to the builder
-       * generated by {@link org.jclouds.cloudwatch.domain.MetricDatum#builder}.
+       * Creates a new builder. The returned builder is equivalent to the builder generated by
+       * {@link org.jclouds.cloudwatch.domain.MetricDatum#builder}.
        */
-      public Builder() {}
+      public Builder() {
+      }
 
       /**
        * A list of dimensions describing qualities of the metric.
-       *
-       * @param dimensions the dimensions describing the qualities of the metric
-       *
+       * 
+       * @param dimensions
+       *           the dimensions describing the qualities of the metric
+       * 
        * @return this {@code Builder} object
        */
-      public Builder dimensions(Set<Dimension> dimensions) {
+      public Builder dimensions(Iterable<Dimension> dimensions) {
          this.dimensions.addAll(checkNotNull(dimensions, "dimensions"));
          return this;
       }
 
       /**
        * A dimension describing qualities of the metric.
-       *
-       * @param dimension the dimension describing the qualities of the metric
-       *
+       * 
+       * @param dimension
+       *           the dimension describing the qualities of the metric
+       * 
        * @return this {@code Builder} object
        */
       public Builder dimension(Dimension dimension) {
@@ -149,9 +154,10 @@
 
       /**
        * The name of the metric.
-       *
-       * @param metricName the metric name
-       *
+       * 
+       * @param metricName
+       *           the metric name
+       * 
        * @return this {@code Builder} object
        */
       public Builder metricName(String metricName) {
@@ -161,34 +167,37 @@
 
       /**
        * The object describing the set of statistical values describing the metric.
-       *
-       * @param statisticValues the object describing the set of statistical values for the metric
-       *
+       * 
+       * @param statisticValues
+       *           the object describing the set of statistical values for the metric
+       * 
        * @return this {@code Builder} object
        */
       public Builder statisticValues(StatisticValues statisticValues) {
-         this.statisticValues = statisticValues;
+         this.statisticValues = Optional.fromNullable(statisticValues);
          return this;
       }
 
       /**
-       * The time stamp used for the metric.  If not specified, the default value is set to the time the metric data was
-       * received.
-       *
-       * @param timestamp the time stamp used for the metric
-       *
+       * The time stamp used for the metric. If not specified, the default value is set to the time
+       * the metric data was received.
+       * 
+       * @param timestamp
+       *           the time stamp used for the metric
+       * 
        * @return this {@code Builder} object
        */
       public Builder timestamp(Date timestamp) {
-         this.timestamp = timestamp;
+         this.timestamp = Optional.fromNullable(timestamp);
          return this;
       }
 
       /**
        * The unit for the metric.
-       *
-       * @param unit the unit for the metric
-       *
+       * 
+       * @param unit
+       *           the unit for the metric
+       * 
        * @return this {@code Builder} object
        */
       public Builder unit(Unit unit) {
@@ -198,13 +207,14 @@
 
       /**
        * The value for the metric.
-       *
-       * @param value the value for the metric
-       *
+       * 
+       * @param value
+       *           the value for the metric
+       * 
        * @return this {@code Builder} object
        */
-      public Builder value(double value) {
-         this.value = value;
+      public Builder value(Double value) {
+         this.value = Optional.fromNullable(value);
          return this;
       }
 
@@ -212,7 +222,7 @@
        * Returns a newly-created {@code MetricDatum} based on the contents of the {@code Builder}.
        */
       public MetricDatum build() {
-         return new MetricDatum(dimensions, metricName, statisticValues, timestamp, unit, value);
+         return new MetricDatum(dimensions.build(), metricName, statisticValues, timestamp, unit, value);
       }
 
    }
@@ -240,7 +250,8 @@
    }
 
    protected ToStringHelper string() {
-      return Objects.toStringHelper("").add("dimensions", dimensions).add("metricName", metricName).add(
-               "statisticValues", statisticValues).add("timestamp", timestamp).add("unit", unit).add("value", value);
+      return Objects.toStringHelper("").omitNullValues().add("dimensions", dimensions).add("metricName", metricName)
+               .add("statisticValues", statisticValues.orNull()).add("timestamp", timestamp.orNull()).add("unit", unit)
+               .add("value", value.orNull());
    }
 }
diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/features/MetricApi.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/features/MetricApi.java
index 9e5deab..a573656 100644
--- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/features/MetricApi.java
+++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/features/MetricApi.java
@@ -34,6 +34,7 @@
  * Provides access to Amazon CloudWatch via the Query API
  * <p/>
  * 
+ * @see MetricAsyncApi
  * @see <a href="http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference" />
  * @author Jeremy Whitlock
  */
diff --git a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/features/MetricAsyncApi.java b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/features/MetricAsyncApi.java
index 3e739b5..3e81380 100644
--- a/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/features/MetricAsyncApi.java
+++ b/apis/cloudwatch/src/main/java/org/jclouds/cloudwatch/features/MetricAsyncApi.java
@@ -37,11 +37,14 @@
 import org.jclouds.collect.IterableWithMarker;
 import org.jclouds.collect.PagedIterable;
 import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.FormParams;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.Transform;
 import org.jclouds.rest.annotations.VirtualHost;
 import org.jclouds.rest.annotations.XMLResponseParser;
+import org.jclouds.rest.functions.ReturnEmptyIterableWithMarkerOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -64,6 +67,7 @@
    @XMLResponseParser(ListMetricsResponseHandler.class)
    @Transform(MetricsToPagedIterable.class)
    @FormParams(keys = "Action", values = "ListMetrics")
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
    ListenableFuture<? extends PagedIterable<Metric>> list();
 
    /**
@@ -73,6 +77,7 @@
    @Path("/")
    @XMLResponseParser(ListMetricsResponseHandler.class)
    @FormParams(keys = "Action", values = "ListMetrics")
+   @ExceptionParser(ReturnEmptyIterableWithMarkerOnNotFoundOr404.class)
    ListenableFuture<? extends IterableWithMarker<Metric>> list(ListMetricsOptions options);
 
    /**
diff --git a/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/binders/MetricDataBinderTest.java b/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/binders/MetricDataBinderTest.java
index 94dcac4..003fb90 100644
--- a/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/binders/MetricDataBinderTest.java
+++ b/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/binders/MetricDataBinderTest.java
@@ -60,7 +60,6 @@
                                            .statisticValues(ss)
                                            .dimension(new Dimension("TestDimension", "FAKE"))
                                            .unit(Unit.COUNT)
-                                           .value(2)
                                            .build();
 
       HttpRequest request = binder.bindToRequest(request(), ImmutableSet.of(metricDatum));
@@ -73,8 +72,7 @@
                                 "&MetricData.member.1.StatisticValues.Minimum=1.0" +
                                 "&MetricData.member.1.StatisticValues.SampleCount=4.0" +
                                 "&MetricData.member.1.StatisticValues.Sum=10.0" +
-                                "&MetricData.member.1.Unit=" + Unit.COUNT.toString() +
-                                "&MetricData.member.1.Value=2.0");
+                                "&MetricData.member.1.Unit=" + Unit.COUNT.toString());
    }
 
    public void testMetricWithMultipleDimensions() throws Exception {
diff --git a/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/features/MetricApiExpectTest.java b/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/features/MetricApiExpectTest.java
index 25cae95..90ff958 100644
--- a/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/features/MetricApiExpectTest.java
+++ b/apis/cloudwatch/src/test/java/org/jclouds/cloudwatch/features/MetricApiExpectTest.java
@@ -33,6 +33,7 @@
 import org.jclouds.cloudwatch.internal.BaseCloudWatchApiExpectTest;
 import org.jclouds.cloudwatch.options.GetMetricStatisticsOptions;
 import org.jclouds.cloudwatch.options.ListMetricsOptions;
+import org.jclouds.collect.IterableWithMarkers;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
 import org.jclouds.rest.ResourceNotFoundException;
@@ -76,8 +77,6 @@
             "[Metric{namespace=AWS/EC2, metricName=CPUUtilization, dimension=[Dimension{name=InstanceId, value=i-689fcf0f}]}]");
    }
 
-   // TODO: this should really be an empty set
-   @Test(expectedExceptions = ResourceNotFoundException.class)
    public void testListMetricsWhenResponseIs404() throws Exception {
 
       HttpResponse listMetricsResponse = HttpResponse.builder().statusCode(404).build();
@@ -85,7 +84,7 @@
       CloudWatchApi apiWhenMetricsDontExist = requestSendsResponse(
             listMetrics, listMetricsResponse);
 
-      apiWhenMetricsDontExist.getMetricApiForRegion(null).list().get(0);
+      assertEquals(apiWhenMetricsDontExist.getMetricApiForRegion(null).list().get(0), IterableWithMarkers.EMPTY);
    }
    
    public void testListMetrics2PagesWhenResponseIs2xx() throws Exception {
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadata.java b/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadata.java
index 7319993..a134ec0 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadata.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadata.java
@@ -196,7 +196,7 @@
 
    @VisibleForTesting
    String getGroupForInstance(final RunningInstance instance) {
-      String group = parseGroupFrom(instance, instance.getGroupIds());
+      String group = parseGroupFrom(instance, instance.getGroupNames());
       if(group == null && instance.getKeyName() != null) {
          // when not using a generated security group, e.g. in VPC, try from key:
          group = parseGroupFrom(instance, Sets.newHashSet(instance.getKeyName()));
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Attachment.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Attachment.java
index 0f1e79b..73a6fee 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Attachment.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Attachment.java
@@ -114,8 +114,12 @@
    }
 
    /**
-    * Snapshots are tied to Regions and can only be used for volumes within the same Region.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/BundleTask.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/BundleTask.java
index 2350044..9ec3bbd 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/BundleTask.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/BundleTask.java
@@ -209,9 +209,12 @@
    }
 
    /**
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
     * 
-    * @return region of the bundle task
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Image.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Image.java
index 99bb4ae..1c50e63 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Image.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Image.java
@@ -219,9 +219,12 @@
    }
 
    /**
-    * AMIs are tied to the Region where its files are located within Amazon S3.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
     * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/InstanceStateChange.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/InstanceStateChange.java
index 3f05187..ab38a4b 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/InstanceStateChange.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/InstanceStateChange.java
@@ -47,8 +47,12 @@
    }
 
    /**
-    * Instances are tied to Availability Zones. However, the instance ID is tied to the Region.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/KeyPair.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/KeyPair.java
index ead73cb..bd927a3 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/KeyPair.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/KeyPair.java
@@ -103,8 +103,12 @@
    }
 
    /**
-    * Key pairs (to connect to instances) are Region-specific.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/PublicIpInstanceIdPair.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/PublicIpInstanceIdPair.java
index 8f03cab..189fe7c 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/PublicIpInstanceIdPair.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/PublicIpInstanceIdPair.java
@@ -42,8 +42,12 @@
    }
 
    /**
-    * Elastic IP addresses are tied to a Region and cannot be mapped across Regions.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Reservation.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Reservation.java
index 48f6d06..5a621b2 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Reservation.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Reservation.java
@@ -20,27 +20,119 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.util.LinkedHashSet;
 import java.util.Set;
 
 import org.jclouds.javax.annotation.Nullable;
 
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
+import com.google.common.base.Objects;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.ForwardingSet;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Ordering;
 
 /**
  * 
- * @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-ReservationInfoType.html"
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-ReservationInfoType.html"
  *      />
  * @author Adrian Cole
  */
-public class Reservation<T extends RunningInstance> extends LinkedHashSet<T> implements Comparable<Reservation<T>>,
-         Set<T> {
+public class Reservation<T extends RunningInstance> extends ForwardingSet<T> implements Comparable<Reservation<T>>{
 
-   /** The serialVersionUID */
-   private static final long serialVersionUID = -9051777593518861395L;
+   public static <T extends RunningInstance> Builder<T> builder() {
+      return new Builder<T>();
+   }
+
+   public Builder<T> toBuilder() {
+      return Reservation.<T> builder().fromReservation(this);
+   }
+
+   public static class Builder<T extends RunningInstance> {
+      private String region;
+      private String ownerId;
+      private String requesterId;
+      private String reservationId;
+
+      private ImmutableSet.Builder<T> instances = ImmutableSet.<T> builder();
+      private ImmutableSet.Builder<String> groupNames = ImmutableSet.<String> builder();
+
+      /**
+       * @see Reservation#getRegion()
+       */
+      public Builder<T> region(String region) {
+         this.region = region;
+         return this;
+      }
+
+      /**
+       * @see Reservation#getOwnerId()
+       */
+      public Builder<T> ownerId(String ownerId) {
+         this.ownerId = ownerId;
+         return this;
+      }
+
+      /**
+       * @see Reservation#getRequesterId()
+       */
+      public Builder<T> requesterId(String requesterId) {
+         this.requesterId = requesterId;
+         return this;
+      }
+
+      /**
+       * @see Reservation#getReservationId()
+       */
+      public Builder<T> reservationId(String reservationId) {
+         this.reservationId = reservationId;
+         return this;
+      }
+
+      /**
+       * @see Reservation#iterator
+       */
+      public Builder<T> instance(T instance) {
+         this.instances.add(checkNotNull(instance, "instance"));
+         return this;
+      }
+
+      /**
+       * @see Reservation#iterator
+       */
+      public Builder<T> instances(Set<T> instances) {
+         this.instances.addAll(checkNotNull(instances, "instances"));
+         return this;
+      }
+
+      /**
+       * @see Reservation#getGroupNames()
+       */
+      public Builder<T> groupName(String groupName) {
+         this.groupNames.add(checkNotNull(groupName, "groupName"));
+         return this;
+      }
+
+      /**
+       * @see Reservation#getGroupNames()
+       */
+      public Builder<T> groupNames(Iterable<String> groupNames) {
+         this.groupNames = ImmutableSet.<String> builder().addAll(checkNotNull(groupNames, "groupNames"));
+         return this;
+      }
+
+      public Reservation<T> build() {
+         return new Reservation<T>(region, groupNames.build(), instances.build(), ownerId, requesterId, reservationId);
+      }
+
+      public Builder<T> fromReservation(Reservation<T> in) {
+         return region(in.region).ownerId(in.ownerId).requesterId(in.requesterId).reservationId(in.reservationId)
+                  .instances(in).groupNames(in.groupNames);
+      }
+   }
+
    private final String region;
-   private final Set<String> groupIds = Sets.newLinkedHashSet();
+   private final ImmutableSet<String> groupNames;
+   private final ImmutableSet<T> instances;
    @Nullable
    private final String ownerId;
    @Nullable
@@ -48,32 +140,45 @@
    @Nullable
    private final String reservationId;
 
-   public Reservation(String region, Iterable<String> groupIds, Iterable<T> instances, @Nullable String ownerId,
+   public Reservation(String region, Iterable<String> groupNames, Iterable<T> instances, @Nullable String ownerId,
             @Nullable String requesterId, @Nullable String reservationId) {
       this.region = checkNotNull(region, "region");
-      Iterables.addAll(this.groupIds, checkNotNull(groupIds, "groupIds"));
-      Iterables.addAll(this, checkNotNull(instances, "instances"));
+      this.groupNames = ImmutableSet.copyOf(checkNotNull(groupNames, "groupNames"));
+      this.instances = ImmutableSet.copyOf(checkNotNull(instances, "instances"));
       this.ownerId = ownerId;
       this.requesterId = requesterId;
       this.reservationId = reservationId;
    }
 
+   @Override
+   protected Set<T> delegate() {
+      return instances;
+   }
+
    /**
-    * Instances are tied to Availability Zones. However, the instance ID is tied to the Region.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
 
-   public int compareTo(Reservation<T> o) {
-      return (this == o) ? 0 : getReservationId().compareTo(o.getReservationId());
+   /**
+    * @see #getGroupNames()
+    */
+   @Deprecated
+   public Set<String> getGroupIds() {
+      return groupNames;
    }
-
+   
    /**
     * Names of the security groups.
     */
-   public Set<String> getGroupIds() {
-      return groupIds;
+   public Set<String> getGroupNames() {
+      return groupNames;
    }
 
    /**
@@ -84,7 +189,8 @@
    }
 
    /**
-    * ID of the requester.
+    * The ID of the requester that launched the instances on your behalf (for example, AWS
+    * Management Console or Auto Scaling).
     */
    public String getRequesterId() {
       return requesterId;
@@ -99,51 +205,34 @@
 
    @Override
    public int hashCode() {
-      final int prime = 31;
-      int result = super.hashCode();
-      result = prime * result + ((groupIds == null) ? 0 : groupIds.hashCode());
-      result = prime * result + ((ownerId == null) ? 0 : ownerId.hashCode());
-      result = prime * result + ((region == null) ? 0 : region.hashCode());
-      result = prime * result + ((requesterId == null) ? 0 : requesterId.hashCode());
-      result = prime * result + ((reservationId == null) ? 0 : reservationId.hashCode());
-      return result;
+      return Objects.hashCode(region, reservationId, super.hashCode());
    }
 
    @Override
    public boolean equals(Object obj) {
       if (this == obj)
          return true;
-      if (!super.equals(obj))
+      if (obj == null || getClass() != obj.getClass())
          return false;
-      if (getClass() != obj.getClass())
-         return false;
-      Reservation<?> other = (Reservation<?>) obj;
-      if (groupIds == null) {
-         if (other.groupIds != null)
-            return false;
-      } else if (!groupIds.equals(other.groupIds))
-         return false;
-      if (ownerId == null) {
-         if (other.ownerId != null)
-            return false;
-      } else if (!ownerId.equals(other.ownerId))
-         return false;
-      if (region == null) {
-         if (other.region != null)
-            return false;
-      } else if (!region.equals(other.region))
-         return false;
-      if (requesterId == null) {
-         if (other.requesterId != null)
-            return false;
-      } else if (!requesterId.equals(other.requesterId))
-         return false;
-      if (reservationId == null) {
-         if (other.reservationId != null)
-            return false;
-      } else if (!reservationId.equals(other.reservationId))
-         return false;
-      return true;
+      @SuppressWarnings("unchecked")
+      Reservation<T> that = Reservation.class.cast(obj);
+      return super.equals(that) && Objects.equal(this.region, that.region)
+               && Objects.equal(this.reservationId, that.reservationId);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("region", region).add("reservationId", reservationId)
+               .add("requesterId", requesterId).add("instances", instances).add("groupNames", groupNames).toString();
+   }
+
+   @Override
+   public int compareTo(Reservation<T> other) {
+      return ComparisonChain.start().compare(region, other.region)
+               .compare(reservationId, other.reservationId, Ordering.natural().nullsLast()).result();
    }
 
 }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/ReservedInstancesOffering.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/ReservedInstancesOffering.java
index f7987de..a1f78e6 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/ReservedInstancesOffering.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/ReservedInstancesOffering.java
@@ -46,10 +46,17 @@
       this.usagePrice = usagePrice;
    }
 
+   /**
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
+    */
+   @Deprecated
    public String getRegion() {
       return region;
    }
-
+   
    /**
     * @return The Availability Zone in which the Reserved Instance can be used.
     */
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/RunningInstance.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/RunningInstance.java
index 0a11cb6..bb4613b 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/RunningInstance.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/RunningInstance.java
@@ -26,9 +26,13 @@
 
 import org.jclouds.javax.annotation.Nullable;
 
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ComparisonChain;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 
 /**
@@ -44,7 +48,7 @@
 
    public static class Builder {
       protected String region;
-      protected Set<String> groupIds = Sets.newLinkedHashSet();
+      protected Set<String> groupNames = Sets.newLinkedHashSet();
       protected String amiLaunchIndex;
       protected String dnsName;
       protected String imageId;
@@ -72,14 +76,14 @@
          return this;
       }
 
-      public Builder groupIds(Iterable<String> groupIds) {
-         this.groupIds = ImmutableSet.copyOf(checkNotNull(groupIds, "groupIds"));
+      public Builder groupNames(Iterable<String> groupNames) {
+         this.groupNames = ImmutableSet.copyOf(checkNotNull(groupNames, "groupNames"));
          return this;
       }
 
-      public Builder groupId(String groupId) {
-         if (groupId != null)
-            this.groupIds.add(groupId);
+      public Builder groupName(String groupName) {
+         if (groupName != null)
+            this.groupNames.add(groupName);
          return this;
       }
 
@@ -195,7 +199,7 @@
       }
 
       public RunningInstance build() {
-         return new RunningInstance(region, groupIds, amiLaunchIndex, dnsName, imageId, instanceId, instanceState,
+         return new RunningInstance(region, groupNames, amiLaunchIndex, dnsName, imageId, instanceId, instanceState,
                   rawState, instanceType, ipAddress, kernelId, keyName, launchTime, availabilityZone,
                   virtualizationType, platform, privateDnsName, privateIpAddress, ramdiskId, reason, rootDeviceType,
                   rootDeviceName, ebsBlockDevices);
@@ -220,7 +224,7 @@
    }
 
    protected final String region;
-   protected final Set<String> groupIds;
+   protected final Set<String> groupNames;
    protected final String amiLaunchIndex;
    @Nullable
    protected final String dnsName;
@@ -253,11 +257,7 @@
    protected final String rootDeviceName;
    protected final Map<String, BlockDevice> ebsBlockDevices;
 
-   public int compareTo(RunningInstance o) {
-      return (this == o) ? 0 : getId().compareTo(o.getId());
-   }
-
-   protected RunningInstance(String region, Iterable<String> groupIds, @Nullable String amiLaunchIndex,
+   protected RunningInstance(String region, Iterable<String> groupNames, @Nullable String amiLaunchIndex,
             @Nullable String dnsName, String imageId, String instanceId, InstanceState instanceState, String rawState,
             String instanceType, @Nullable String ipAddress, @Nullable String kernelId, @Nullable String keyName,
             Date launchTime, String availabilityZone, String virtualizationType, @Nullable String platform,
@@ -286,12 +286,16 @@
       this.rootDeviceType = checkNotNull(rootDeviceType, "rootDeviceType for %s/%s", region, instanceId);
       this.rootDeviceName = rootDeviceName;
       this.ebsBlockDevices = ImmutableMap.copyOf(checkNotNull(ebsBlockDevices, "ebsBlockDevices for %s/%s", region, instanceId));
-      this.groupIds = ImmutableSet.copyOf(checkNotNull(groupIds, "groupIds for %s/%s", region, instanceId));
+      this.groupNames = ImmutableSet.copyOf(checkNotNull(groupNames, "groupNames for %s/%s", region, instanceId));
    }
 
    /**
-    * Instance Ids are scoped to the region.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
@@ -444,159 +448,54 @@
    }
 
    /**
+    * @see #getGroupNames()
+    */
+   @Deprecated
+   public Set<String> getGroupIds() {
+      return getGroupNames();
+   }
+   
+   /**
     * Names of the security groups.
     */
-   public Set<String> getGroupIds() {
-      return groupIds;
+   public Set<String> getGroupNames() {
+      return groupNames;
    }
 
    @Override
+   public int compareTo(RunningInstance other) {
+      return ComparisonChain.start().compare(region, other.region).compare(instanceId, other.instanceId, Ordering.natural().nullsLast()).result();
+   }
+   
+   @Override
    public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result = prime * result + ((amiLaunchIndex == null) ? 0 : amiLaunchIndex.hashCode());
-      result = prime * result + ((availabilityZone == null) ? 0 : availabilityZone.hashCode());
-      result = prime * result + ((dnsName == null) ? 0 : dnsName.hashCode());
-      result = prime * result + ((ebsBlockDevices == null) ? 0 : ebsBlockDevices.hashCode());
-      result = prime * result + ((groupIds == null) ? 0 : groupIds.hashCode());
-      result = prime * result + ((imageId == null) ? 0 : imageId.hashCode());
-      result = prime * result + ((instanceId == null) ? 0 : instanceId.hashCode());
-      result = prime * result + ((instanceType == null) ? 0 : instanceType.hashCode());
-      result = prime * result + ((ipAddress == null) ? 0 : ipAddress.hashCode());
-      result = prime * result + ((kernelId == null) ? 0 : kernelId.hashCode());
-      result = prime * result + ((keyName == null) ? 0 : keyName.hashCode());
-      result = prime * result + ((launchTime == null) ? 0 : launchTime.hashCode());
-      result = prime * result + ((platform == null) ? 0 : platform.hashCode());
-      result = prime * result + ((privateDnsName == null) ? 0 : privateDnsName.hashCode());
-      result = prime * result + ((privateIpAddress == null) ? 0 : privateIpAddress.hashCode());
-      result = prime * result + ((ramdiskId == null) ? 0 : ramdiskId.hashCode());
-      result = prime * result + ((region == null) ? 0 : region.hashCode());
-      result = prime * result + ((rootDeviceName == null) ? 0 : rootDeviceName.hashCode());
-      result = prime * result + ((rootDeviceType == null) ? 0 : rootDeviceType.hashCode());
-      result = prime * result + ((virtualizationType == null) ? 0 : virtualizationType.hashCode());
-      return result;
+      return Objects.hashCode(region, instanceId);
    }
 
    @Override
    public boolean equals(Object obj) {
       if (this == obj)
          return true;
-      if (obj == null)
+      if (obj == null || getClass() != obj.getClass())
          return false;
-      if (getClass() != obj.getClass())
-         return false;
-      RunningInstance other = (RunningInstance) obj;
-      if (amiLaunchIndex == null) {
-         if (other.amiLaunchIndex != null)
-            return false;
-      } else if (!amiLaunchIndex.equals(other.amiLaunchIndex))
-         return false;
-      if (availabilityZone == null) {
-         if (other.availabilityZone != null)
-            return false;
-      } else if (!availabilityZone.equals(other.availabilityZone))
-         return false;
-      if (dnsName == null) {
-         if (other.dnsName != null)
-            return false;
-      } else if (!dnsName.equals(other.dnsName))
-         return false;
-      if (ebsBlockDevices == null) {
-         if (other.ebsBlockDevices != null)
-            return false;
-      } else if (!ebsBlockDevices.equals(other.ebsBlockDevices))
-         return false;
-      if (groupIds == null) {
-         if (other.groupIds != null)
-            return false;
-      } else if (!groupIds.equals(other.groupIds))
-         return false;
-      if (imageId == null) {
-         if (other.imageId != null)
-            return false;
-      } else if (!imageId.equals(other.imageId))
-         return false;
-      if (instanceId == null) {
-         if (other.instanceId != null)
-            return false;
-      } else if (!instanceId.equals(other.instanceId))
-         return false;
-      if (instanceType == null) {
-         if (other.instanceType != null)
-            return false;
-      } else if (!instanceType.equals(other.instanceType))
-         return false;
-      if (ipAddress == null) {
-         if (other.ipAddress != null)
-            return false;
-      } else if (!ipAddress.equals(other.ipAddress))
-         return false;
-      if (kernelId == null) {
-         if (other.kernelId != null)
-            return false;
-      } else if (!kernelId.equals(other.kernelId))
-         return false;
-      if (keyName == null) {
-         if (other.keyName != null)
-            return false;
-      } else if (!keyName.equals(other.keyName))
-         return false;
-      if (launchTime == null) {
-         if (other.launchTime != null)
-            return false;
-      } else if (!launchTime.equals(other.launchTime))
-         return false;
-      if (platform == null) {
-         if (other.platform != null)
-            return false;
-      } else if (!platform.equals(other.platform))
-         return false;
-      if (privateDnsName == null) {
-         if (other.privateDnsName != null)
-            return false;
-      } else if (!privateDnsName.equals(other.privateDnsName))
-         return false;
-      if (privateIpAddress == null) {
-         if (other.privateIpAddress != null)
-            return false;
-      } else if (!privateIpAddress.equals(other.privateIpAddress))
-         return false;
-      if (ramdiskId == null) {
-         if (other.ramdiskId != null)
-            return false;
-      } else if (!ramdiskId.equals(other.ramdiskId))
-         return false;
-      if (region == null) {
-         if (other.region != null)
-            return false;
-      } else if (!region.equals(other.region))
-         return false;
-      if (rootDeviceName == null) {
-         if (other.rootDeviceName != null)
-            return false;
-      } else if (!rootDeviceName.equals(other.rootDeviceName))
-         return false;
-      if (rootDeviceType == null) {
-         if (other.rootDeviceType != null)
-            return false;
-      } else if (!rootDeviceType.equals(other.rootDeviceType))
-         return false;
-      if (virtualizationType == null) {
-         if (other.virtualizationType != null)
-            return false;
-      } else if (!virtualizationType.equals(other.virtualizationType))
-         return false;
-      return true;
+      RunningInstance that = RunningInstance.class.cast(obj);
+      return Objects.equal(this.region, that.region) && Objects.equal(this.instanceId, that.instanceId);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this).omitNullValues().add("region", region)
+               .add("availabilityZone", availabilityZone).add("id", instanceId).add("state", rawState)
+               .add("type", instanceType).add("virtualizationType", virtualizationType).add("imageId", imageId)
+               .add("ipAddress", ipAddress).add("dnsName", dnsName).add("privateIpAddress", privateIpAddress)
+               .add("privateDnsName", privateDnsName).add("keyName", keyName).add("groupNames", groupNames)
+               .add("platform", platform).add("launchTime", launchTime).add("rootDeviceName", rootDeviceName)
+               .add("rootDeviceType", rootDeviceType).add("ebsBlockDevices", ebsBlockDevices);
    }
 
    @Override
    public String toString() {
-      return "[region=" + region + ", availabilityZone=" + availabilityZone + ", instanceId=" + instanceId
-               + ", instanceState=" + rawState + ", instanceType=" + instanceType + ", virtualizationType="
-               + virtualizationType + ", imageId=" + imageId + ", ipAddress=" + ipAddress + ", dnsName=" + dnsName
-               + ", privateIpAddress=" + privateIpAddress + ", privateDnsName=" + privateDnsName + ", keyName="
-               + keyName + ", groupIds=" + groupIds  + ", platform=" + platform + ", launchTime=" + launchTime + ", rootDeviceName="
-               + rootDeviceName + ", rootDeviceType=" + rootDeviceType + ", ebsBlockDevices=" + ebsBlockDevices + "]";
+      return string().toString();
    }
 
+
 }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/SecurityGroup.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/SecurityGroup.java
index ebf1f6d..ee39cc5 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/SecurityGroup.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/SecurityGroup.java
@@ -31,7 +31,7 @@
  *      />
  * @author Adrian Cole
  */
-public class SecurityGroup implements Comparable<SecurityGroup> {
+public class SecurityGroup {
 
    private final String region;
    private final String id;
@@ -49,25 +49,19 @@
       this.description = description;
       this.ipPermissions = ipPermissions;
    }
-
+   
    /**
-    * Security groups are not copied across Regions. Instances within the Region
-    * cannot communicate with instances outside the Region using group-based
-    * firewall rules. Traffic from instances in another Region is seen as WAN
-    * bandwidth.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
 
    /**
-    * {@inheritDoc}
-    */
-   public int compareTo(SecurityGroup o) {
-      return (this == o) ? 0 : getName().compareTo(o.getName());
-   }
-
-   /**
     * id of the security group. Not in all EC2 impls
     */
    @Nullable
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Snapshot.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Snapshot.java
index f01d01a..8acfbff 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Snapshot.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Snapshot.java
@@ -75,12 +75,16 @@
    }
 
    /**
-    * Snapshots are tied to Regions and can only be used for volumes within the same Region.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
-
+   
    /**
     * The ID of the snapshot.
     */
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Volume.java b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Volume.java
index 427560b..f264e18 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/domain/Volume.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/domain/Volume.java
@@ -172,9 +172,12 @@
    }
 
    /**
-    * An Amazon EBS volume must be located within the same Availability Zone as the instance to
-    * which it attaches.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/xml/BaseReservationHandler.java b/apis/ec2/src/main/java/org/jclouds/ec2/xml/BaseReservationHandler.java
index 33cb755..56ef820 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/xml/BaseReservationHandler.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/xml/BaseReservationHandler.java
@@ -80,7 +80,7 @@
    private String deviceName;
 
    // reservation stuff
-   private Set<String> groupIds = Sets.newLinkedHashSet();
+   private Set<String> groupNames = Sets.newLinkedHashSet();
    private String ownerId;
    private String requesterId;
    private String reservationId;
@@ -111,7 +111,7 @@
       } else if (equalsOrSuffix(qName, "groupSet")) {
          inGroupSet = false;
       } else if (equalsOrSuffix(qName, "groupId")) {
-         groupIds.add(currentOrNull(currentText));
+         groupNames.add(currentOrNull(currentText));
       } else if (equalsOrSuffix(qName, "ownerId")) {
          ownerId = currentOrNull(currentText);
       } else if (equalsOrSuffix(qName, "requesterId")) {
@@ -210,7 +210,7 @@
       }
 
       builder.region((region == null) ? defaultRegion.get() : region);
-      builder.groupIds(groupIds);
+      builder.groupNames(groupNames);
    }
 
    protected Builder builder() {
@@ -229,9 +229,9 @@
       String region = getRequest() != null ? AWSUtils.findRegionInArgsOrNull(getRequest()) : null;
       if (region == null)
          region = defaultRegion.get();
-      Reservation<? extends RunningInstance> info = new Reservation<RunningInstance>(region, groupIds, instances,
+      Reservation<? extends RunningInstance> info = new Reservation<RunningInstance>(region, groupNames, instances,
             ownerId, requesterId, reservationId);
-      this.groupIds = Sets.newLinkedHashSet();
+      this.groupNames = Sets.newLinkedHashSet();
       this.instances = Sets.newLinkedHashSet();
       this.ownerId = null;
       this.requesterId = null;
diff --git a/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSecurityGroupsResponseHandler.java b/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSecurityGroupsResponseHandler.java
index 9b1b53d..96cb1d1 100644
--- a/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSecurityGroupsResponseHandler.java
+++ b/apis/ec2/src/main/java/org/jclouds/ec2/xml/DescribeSecurityGroupsResponseHandler.java
@@ -130,7 +130,8 @@
             this.ipProtocol = null;
             this.ipRanges = Sets.newLinkedHashSet();
          } else if (inIpPermissions && !inIpRanges && inGroups) {
-            this.groups.put(userId, userIdGroupName);
+            if (userId != null && userIdGroupName != null)
+               this.groups.put(userId, userIdGroupName);
             this.userId = null;
             this.userIdGroupName = null;
          } else if (!inIpPermissions && !inIpRanges && !inGroups) {
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceLiveTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceLiveTest.java
index b204a07..f8ae751 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceLiveTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/EC2ComputeServiceLiveTest.java
@@ -151,7 +151,7 @@
          assertEquals(instance.getKeyName(), group);
 
          // make sure we made our dummy group and also let in the user's group
-         assertEquals(Sets.newTreeSet(instance.getGroupIds()), ImmutableSortedSet.<String> of("jclouds#" + group + "#"
+         assertEquals(Sets.newTreeSet(instance.getGroupNames()), ImmutableSortedSet.<String> of("jclouds#" + group + "#"
                   + instance.getRegion(), group));
 
          // make sure our dummy group has no rules
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadataTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadataTest.java
index f677c32..75e5016 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadataTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/compute/functions/RunningInstanceToNodeMetadataTest.java
@@ -241,13 +241,13 @@
    public void testGroupNameIsSetWhenCustomKeyNameIsSetAndSecurityGroupIsGenerated() {
       checkGroupName(RunningInstance.builder().instanceId("id").imageId("image").instanceType("m1.small")
               .instanceState(InstanceState.RUNNING).rawState("running").region("us-east-1").keyName("custom-key")
-              .groupId("jclouds#groupname").build());
+              .groupName("jclouds#groupname").build());
    }
 
    @Test
    public void testGroupNameIsSetWhenCustomSecurityGroupIsSetAndKeyNameIsGenerated() {
       checkGroupName(RunningInstance.builder().instanceId("id").imageId("image").instanceType("m1.small")
-              .instanceState(InstanceState.RUNNING).rawState("running").region("us-east-1").groupId("custom-sec")
+              .instanceState(InstanceState.RUNNING).rawState("running").region("us-east-1").groupName("custom-sec")
               .keyName("jclouds#groupname#23").build());
    }
 
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/services/SecurityGroupClientLiveTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/services/SecurityGroupClientLiveTest.java
index 0f0c9e6..3cfa773 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/services/SecurityGroupClientLiveTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/services/SecurityGroupClientLiveTest.java
@@ -23,7 +23,6 @@
 
 import java.util.Iterator;
 import java.util.Set;
-import java.util.SortedSet;
 
 import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
 import org.jclouds.ec2.EC2ApiMetadata;
@@ -32,14 +31,12 @@
 import org.jclouds.ec2.domain.IpProtocol;
 import org.jclouds.ec2.domain.SecurityGroup;
 import org.jclouds.ec2.domain.UserIdGroupPair;
-import org.testng.annotations.AfterTest;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Iterables;
 
 /**
@@ -67,15 +64,13 @@
    @Test
    void testDescribe() {
       for (String region : ec2Client.getConfiguredRegions()) {
-         SortedSet<SecurityGroup> allResults = ImmutableSortedSet.<SecurityGroup> copyOf(client
-               .describeSecurityGroupsInRegion(region));
+         Set<SecurityGroup> allResults = client.describeSecurityGroupsInRegion(region);
          assertNotNull(allResults);
          if (allResults.size() >= 1) {
-            SecurityGroup group = allResults.last();
-            SortedSet<SecurityGroup> result = ImmutableSortedSet.<SecurityGroup> copyOf(client
-                  .describeSecurityGroupsInRegion(region, group.getName()));
+            SecurityGroup group = Iterables.getLast(allResults);
+            Set<SecurityGroup> result = client.describeSecurityGroupsInRegion(region, group.getName());
             assertNotNull(result);
-            SecurityGroup compare = result.last();
+            SecurityGroup compare = Iterables.getLast(result);
             assertEquals(compare, group);
          }
       }
@@ -233,8 +228,7 @@
    }
 
    protected void ensureGroupsExist(String group1Name, String group2Name) {
-      SortedSet<SecurityGroup> twoResults = ImmutableSortedSet.copyOf(client.describeSecurityGroupsInRegion(null,
-            group1Name, group2Name));
+      Set<SecurityGroup> twoResults = client.describeSecurityGroupsInRegion(null, group1Name, group2Name);
       assertNotNull(twoResults);
       assertEquals(twoResults.size(), 2);
       Iterator<SecurityGroup> iterator = twoResults.iterator();
@@ -279,8 +273,4 @@
 
    public static final String PREFIX = System.getProperty("user.name") + "-ec2";
 
-   @AfterTest
-   public void shutdown() {
-      view.close();
-   }
 }
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/xml/DescribeInstancesResponseHandlerTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/xml/DescribeInstancesResponseHandlerTest.java
index ebdeba4..24376d8 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/xml/DescribeInstancesResponseHandlerTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/xml/DescribeInstancesResponseHandlerTest.java
@@ -70,7 +70,7 @@
 
       Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion,
                ImmutableSet.of("adriancole.ec2ingress"), ImmutableSet.of(new RunningInstance.Builder().region(
-                        defaultRegion).groupId("adriancole.ec2ingress").amiLaunchIndex("0").dnsName(
+                        defaultRegion).groupName("adriancole.ec2ingress").amiLaunchIndex("0").dnsName(
                         "ec2-174-129-81-68.compute-1.amazonaws.com").imageId("ami-82e4b5c7").instanceId("i-0799056f")
                         .instanceState(InstanceState.RUNNING).rawState("running").instanceType(InstanceType.M1_SMALL)
                         .ipAddress("174.129.81.68").kernelId("aki-a71cf9ce").keyName("adriancole.ec21").launchTime(
@@ -83,7 +83,7 @@
 
       Set<Reservation<? extends RunningInstance>> result = parseRunningInstances("/describe_instances_running.xml");
 
-      assertEquals(result, contents);
+      assertEquals(result.toString(), contents.toString());
       assertEquals(get(get(result, 0), 0).getInstanceState(), InstanceState.RUNNING);
       assertEquals(get(get(result, 0), 0).getRawState(), "running");
 
@@ -91,7 +91,7 @@
 
    public void testApplyInputStream() {
       Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion,
-               ImmutableSet.of("default"), ImmutableSet.of(new RunningInstance.Builder().region(defaultRegion).groupId(
+               ImmutableSet.of("default"), ImmutableSet.of(new RunningInstance.Builder().region(defaultRegion).groupName(
                         "default").amiLaunchIndex("23").dnsName("ec2-72-44-33-4.compute-1.amazonaws.com").imageId(
                         "ami-6ea54007").instanceId("i-28a64341").instanceState(InstanceState.RUNNING).rawState(
                         "running").instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName(
@@ -101,7 +101,7 @@
                                  "10-251-50-132.ec2.internal")// product codes
                         // ImmutableSet.of("774F4FF8")
                         .ramdiskId("ari-badbad00").rootDeviceType(RootDeviceType.INSTANCE_STORE).build(),
-                        new RunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("23")
+                        new RunningInstance.Builder().region(defaultRegion).groupName("default").amiLaunchIndex("23")
                                  .dnsName("ec2-72-44-33-6.compute-1.amazonaws.com").imageId("ami-6ea54007").instanceId(
                                           "i-28a64435").instanceState(InstanceState.RUNNING).rawState("running")
                                  .instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName(
@@ -116,7 +116,7 @@
 
       Set<Reservation<? extends RunningInstance>> result = parseRunningInstances("/describe_instances.xml");
 
-      assertEquals(result, contents);
+      assertEquals(result.toString(), contents.toString());
       assertEquals(get(get(result, 0), 0).getInstanceState(), InstanceState.RUNNING);
       assertEquals(get(get(result, 0), 0).getRawState(), "running");
 
@@ -126,7 +126,7 @@
 
       Set<Reservation<RunningInstance>> contents = ImmutableSet.of(new Reservation<RunningInstance>(defaultRegion,
                ImmutableSet.of("adriancole.ec2ebsingress"), ImmutableSet.of(new RunningInstance.Builder().region(
-                        defaultRegion).groupId("adriancole.ec2ebsingress").amiLaunchIndex("0").dnsName(
+                        defaultRegion).groupName("adriancole.ec2ebsingress").amiLaunchIndex("0").dnsName(
                         "ec2-75-101-203-146.compute-1.amazonaws.com").imageId("ami-849875ed").instanceId("i-e564438d")
                         .instanceState(InstanceState.RUNNING).rawState("running").instanceType(InstanceType.M1_SMALL)
                         .ipAddress("75.101.203.146").kernelId("aki-a71cf9ce")
@@ -145,7 +145,7 @@
 
       Set<Reservation<? extends RunningInstance>> result = parseRunningInstances("/describe_instances_ebs.xml");
 
-      assertEquals(result, contents);
+      assertEquals(result.toString(), contents.toString());
       assertEquals(get(get(result, 0), 0).getInstanceState(), InstanceState.RUNNING);
       assertEquals(get(get(result, 0), 0).getRawState(), "running");
    }
diff --git a/apis/ec2/src/test/java/org/jclouds/ec2/xml/RunInstancesResponseHandlerTest.java b/apis/ec2/src/test/java/org/jclouds/ec2/xml/RunInstancesResponseHandlerTest.java
index 0b23ebf..1b37c53 100644
--- a/apis/ec2/src/test/java/org/jclouds/ec2/xml/RunInstancesResponseHandlerTest.java
+++ b/apis/ec2/src/test/java/org/jclouds/ec2/xml/RunInstancesResponseHandlerTest.java
@@ -65,19 +65,19 @@
       Reservation<? extends RunningInstance> expected = new Reservation<RunningInstance>(defaultRegion, ImmutableSet
                .of("default"), ImmutableSet.of(
 
-      new RunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("0")
+      new RunningInstance.Builder().region(defaultRegion).groupName("default").amiLaunchIndex("0")
                .imageId("ami-60a54009").instanceId("i-2ba64342").instanceState(InstanceState.PENDING).rawState(
                         "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
                         dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED,
                .availabilityZone("us-east-1b").build(),
 
-      new RunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("1")
+      new RunningInstance.Builder().region(defaultRegion).groupName("default").amiLaunchIndex("1")
                .imageId("ami-60a54009").instanceId("i-2bc64242").instanceState(InstanceState.PENDING).rawState(
                         "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
                         dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED,
                .availabilityZone("us-east-1b").build(),
 
-      new RunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("2")
+      new RunningInstance.Builder().region(defaultRegion).groupName("default").amiLaunchIndex("2")
                .imageId("ami-60a54009").instanceId("i-2be64332").instanceState(InstanceState.PENDING).rawState(
                         "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
                         dateService.iso8601DateParse("2007-08-07T11:51:50.000Z"))// MonitoringState.ENABLED,
@@ -96,9 +96,9 @@
       InputStream is = getClass().getResourceAsStream("/run_instances_cloudbridge.xml");
 
       Reservation<? extends RunningInstance> expected = new Reservation<RunningInstance>(defaultRegion, ImmutableSet
-               .of("default"), ImmutableSet.of(
+               .of("jclouds#greenqloud-computeblock"), ImmutableSet.of(
 
-      new RunningInstance.Builder().region(defaultRegion).groupId("jclouds#greenqloud-computeblock").amiLaunchIndex("0")
+      new RunningInstance.Builder().region(defaultRegion).groupName("jclouds#greenqloud-computeblock").amiLaunchIndex("0")
                .imageId("qmi-9ac92558").instanceId("i-01b0dac3").instanceState(InstanceState.PENDING).rawState(
                         "pending").instanceType(InstanceType.M1_SMALL).keyName("jclouds#greenqloud-computeblock#35")
                         .launchTime(dateService.iso8601DateParse("2012-06-15T19:06:35.000+00:00"))
diff --git a/apis/elasticstack/pom.xml b/apis/elasticstack/pom.xml
index 5be2dad..8844449 100644
--- a/apis/elasticstack/pom.xml
+++ b/apis/elasticstack/pom.xml
@@ -33,27 +33,13 @@
   <description>jclouds components to access elasticstack</description>
   <packaging>bundle</packaging>
   
-  <!-- bootstrapping: need to fetch the project POM -->
-  <repositories>
-    <repository>
-      <id>sonatype-nexus-snapshots</id>
-      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
-      <releases>
-        <enabled>false</enabled>
-      </releases>
-      <snapshots>
-        <enabled>true</enabled>
-      </snapshots>
-    </repository>  
-  </repositories>
-  
   <properties>
     <test.elasticstack.endpoint>https://api-lon-p.elastichosts.com</test.elasticstack.endpoint>
-    <test.elasticstack.api-version>1.0</test.elasticstack.api-version>
-    <test.elasticstack.build-version />
+    <test.elasticstack.api-version>2.0</test.elasticstack.api-version>
+    <test.elasticstack.build-version></test.elasticstack.build-version>
     <test.elasticstack.identity>FIXME</test.elasticstack.identity>
     <test.elasticstack.credential>FIXME</test.elasticstack.credential>
-    <test.elasticstack.template>imageId=38df0986-4d85-4b76-b502-3878ffc80161</test.elasticstack.template>
+    <test.elasticstack.template>imageId=38df0986-4d85-4b76-b502-3878ffc80161,loginUser=toor</test.elasticstack.template>
     <jclouds.osgi.export>org.jclouds.elasticstack*;version="${project.version}"</jclouds.osgi.export>
     <jclouds.osgi.import>
       org.jclouds.compute.internal;version="${project.version}",
diff --git a/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java b/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
index adce2eb..217f71a 100644
--- a/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
+++ b/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceAdapter.java
@@ -122,7 +122,8 @@
       }
 
       Server toCreate = small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam())
-            .cpu((int) (template.getHardware().getProcessors().get(0).getSpeed())).build();
+               .cpu((int) (template.getHardware().getProcessors().get(0).getSpeed()))
+               .tags(template.getOptions().getTags()).userMetadata(template.getOptions().getUserMetadata()).build();
 
       ServerInfo from = client.createServer(toCreate);
       client.startServer(from.getUuid());
diff --git a/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/functions/ServerInfoToNodeMetadata.java b/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/functions/ServerInfoToNodeMetadata.java
index 887d0f3..27f648f 100644
--- a/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/functions/ServerInfoToNodeMetadata.java
+++ b/apis/elasticstack/src/main/java/org/jclouds/elasticstack/compute/functions/ServerInfoToNodeMetadata.java
@@ -93,7 +93,8 @@
       builder.name(from.getName());
       builder.location(locationSupplier.get());
       builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getName()));
-
+      builder.tags(from.getTags());
+      builder.userMetadata(from.getUserMetadata());
       String imageId = getImageIdFromServer.apply(from);
       if (imageId != null) {
          Image image = findImageForId.apply(imageId);
diff --git a/apis/elasticstack/src/test/java/org/jclouds/elasticstack/ElasticStackClientLiveTest.java b/apis/elasticstack/src/test/java/org/jclouds/elasticstack/ElasticStackClientLiveTest.java
index badcb39..5dcca7e 100644
--- a/apis/elasticstack/src/test/java/org/jclouds/elasticstack/ElasticStackClientLiveTest.java
+++ b/apis/elasticstack/src/test/java/org/jclouds/elasticstack/ElasticStackClientLiveTest.java
@@ -50,7 +50,7 @@
 import org.jclouds.sshj.config.SshjSshClientModule;
 import org.jclouds.util.Strings2;
 import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Predicate;
@@ -67,10 +67,8 @@
  * @author Adrian Cole
  */
 @Test(groups = "live", singleThreaded = true, testName = "ElasticStackClientLiveTest")
-public class ElasticStackClientLiveTest
-      extends
-      BaseComputeServiceContextLiveTest {
-   
+public class ElasticStackClientLiveTest extends BaseComputeServiceContextLiveTest {
+
    public ElasticStackClientLiveTest() {
       provider = "elasticstack";
    }
@@ -84,23 +82,19 @@
    protected Predicate<DriveInfo> driveNotClaimed;
    protected String imageId;
 
-   @BeforeGroups(groups = { "integration", "live" })
    @Override
+   @BeforeClass(groups = { "integration", "live" })
    public void setupContext() {
       super.setupContext();
-      cloudStackContext = view.unwrap();
+      imageId = view.getComputeService().templateBuilder().build().getImage().getId();
          
-      client = cloudStackContext.getApi();
+      client = view.unwrap(ElasticStackApiMetadata.CONTEXT_TOKEN).getApi();
       driveNotClaimed = new RetryablePredicate<DriveInfo>(Predicates.not(new DriveClaimed(client)), maxDriveImageTime,
                1, TimeUnit.SECONDS);
       socketTester = new RetryablePredicate<HostAndPort>(new InetSocketAddressConnect(), maxDriveImageTime, 1,
                TimeUnit.SECONDS);
-      
-      if (template == null || template.getImageId() == null) {
-         imageId = view.getComputeService().templateBuilder().build().getImage().getId();
-      }
    }
-
+   
    @Test
    public void testListServers() throws Exception {
       Set<String> servers = client.listServers();
diff --git a/apis/elasticstack/src/test/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceLiveTest.java b/apis/elasticstack/src/test/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceLiveTest.java
index 98af64b..82829c6 100644
--- a/apis/elasticstack/src/test/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceLiveTest.java
+++ b/apis/elasticstack/src/test/java/org/jclouds/elasticstack/compute/ElasticStackComputeServiceLiveTest.java
@@ -24,13 +24,12 @@
 import org.jclouds.sshj.config.SshjSshClientModule;
 import org.testng.annotations.Test;
 
-import com.google.common.collect.ImmutableMap;
 import com.google.inject.Module;
 
 /**
  * @author Adrian Cole
  */
-@Test(groups = "live")
+@Test(groups = "live", testName = "ElasticStackComputeServiceLiveTest")
 public class ElasticStackComputeServiceLiveTest extends BaseComputeServiceLiveTest {
 
    public ElasticStackComputeServiceLiveTest() {
@@ -42,13 +41,6 @@
       return new SshjSshClientModule();
    }
 
-   // elasticstack does not support metadata
-   @Override
-   protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
-      assert node.getUserMetadata().equals(ImmutableMap.<String, String> of()) : String.format(
-            "node userMetadata did not match %s %s", userMetadata, node);
-   }
-
    @Override
    public void testOptionToNotBlock() {
       // start call is blocking anyway.
@@ -56,6 +48,6 @@
 
    protected void checkResponseEqualsHostname(ExecResponse execResponse, NodeMetadata node1) {
       // hostname is not predictable based on node metadata
-      assert execResponse.getOutput().trim().equals("ubuntu");
+      assert execResponse.getOutput().trim().equals("ubuntu") : execResponse.getOutput();
    }
 }
diff --git a/apis/filesystem/src/test/java/org/jclouds/filesystem/FilesystemAsyncBlobStoreTest.java b/apis/filesystem/src/test/java/org/jclouds/filesystem/FilesystemAsyncBlobStoreTest.java
index 2aa6079..4dfa8cc 100644
--- a/apis/filesystem/src/test/java/org/jclouds/filesystem/FilesystemAsyncBlobStoreTest.java
+++ b/apis/filesystem/src/test/java/org/jclouds/filesystem/FilesystemAsyncBlobStoreTest.java
@@ -60,7 +60,6 @@
 import org.jclouds.io.payloads.StringPayload;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import com.google.common.io.ByteStreams;
diff --git a/apis/filesystem/src/test/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImplTest.java b/apis/filesystem/src/test/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImplTest.java
index f3790c1..583b644 100644
--- a/apis/filesystem/src/test/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImplTest.java
+++ b/apis/filesystem/src/test/java/org/jclouds/filesystem/strategy/internal/FilesystemStorageStrategyImplTest.java
@@ -46,7 +46,6 @@
 import org.jclouds.io.payloads.FilePayload;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
 import com.google.common.io.ByteStreams;
diff --git a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Resource.java b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Resource.java
index 53ff322..ba6c597 100644
--- a/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Resource.java
+++ b/apis/nova/src/main/java/org/jclouds/openstack/nova/domain/Resource.java
@@ -20,7 +20,6 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.beans.ConstructorProperties;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.List;
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/KeystoneApi.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/KeystoneApi.java
index 125b9ec..2e83b5a 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/KeystoneApi.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/KeystoneApi.java
@@ -21,8 +21,6 @@
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
-import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.location.functions.ZoneToEndpoint;
 import org.jclouds.openstack.keystone.v2_0.domain.ApiMetadata;
 import org.jclouds.openstack.keystone.v2_0.features.ServiceApi;
 import org.jclouds.openstack.keystone.v2_0.features.TenantApi;
@@ -30,7 +28,6 @@
 import org.jclouds.openstack.keystone.v2_0.features.UserApi;
 import org.jclouds.openstack.v2_0.features.ExtensionApi;
 import org.jclouds.rest.annotations.Delegate;
-import org.jclouds.rest.annotations.EndpointParam;
 
 import com.google.common.base.Optional;
 
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneRestClientModule.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneRestClientModule.java
index f473be2..ac8d343 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneRestClientModule.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/config/KeystoneRestClientModule.java
@@ -143,7 +143,7 @@
             .build(CacheLoader.from(Suppliers.memoize(new Supplier<Set<? extends Extension>>() {
                @Override
                public Set<? extends Extension> get() {
-                  return keystoneApi.get().getExtensionApi().listExtensions();
+                  return keystoneApi.get().getExtensionApi().list();
                }
             })));
    }
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/domain/Access.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/domain/Access.java
index ca5745a..c4baf00 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/domain/Access.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/domain/Access.java
@@ -23,6 +23,8 @@
 import java.beans.ConstructorProperties;
 import java.util.Set;
 
+import org.jclouds.javax.annotation.Nullable;
+
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableSet;
@@ -105,10 +107,10 @@
    @ConstructorProperties({
          "token", "user", "serviceCatalog"
    })
-   protected Access(Token token, User user, Set<Service> serviceCatalog) {
+   protected Access(Token token, User user, @Nullable Set<Service> serviceCatalog) {
       this.token = checkNotNull(token, "token");
       this.user = checkNotNull(user, "user");
-      this.serviceCatalog = ImmutableSet.copyOf(checkNotNull(serviceCatalog, "serviceCatalog"));
+      this.serviceCatalog = serviceCatalog == null ? ImmutableSet.<Service>of() : ImmutableSet.copyOf(serviceCatalog);
    }
 
    /**
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/domain/PaginatedCollection.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/domain/PaginatedCollection.java
new file mode 100644
index 0000000..2d87580
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/domain/PaginatedCollection.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.keystone.v2_0.domain;
+
+import static org.jclouds.http.utils.Queries.parseQueryToMap;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/**
+ * base class for a paginated collection in openstack
+ * 
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-identity-service/2.0/content/Paginated_Collections-d1e325.html">
+ *      docs</a>
+ * @author Adrian Cole
+ */
+@Beta
+public class PaginatedCollection<T> extends IterableWithMarker<T> {
+
+   @SuppressWarnings({ "rawtypes", "unchecked" })
+   public static final PaginatedCollection EMPTY = new PaginatedCollection(ImmutableSet.of(), ImmutableSet.of());
+
+   private Iterable<T> resources;
+   private Iterable<Link> links;
+
+   protected PaginatedCollection(Iterable<T> resources, Iterable<Link> links) {
+      this.resources = resources != null ? resources : ImmutableSet.<T> of();
+      this.links = links != null ? links : ImmutableSet.<Link> of();
+   }
+
+   @Override
+   public Iterator<T> iterator() {
+      return resources.iterator();
+   }
+
+   /**
+    * links that relate to this collection
+    */
+   public Iterable<Link> getLinks() {
+      return links;
+   }
+
+   @Override
+   public Optional<Object> nextMarker() {
+      return FluentIterable.from(getLinks()).filter(new Predicate<Link>() {
+         @Override
+         public boolean apply(Link link) {
+            return Link.Relation.NEXT == link.getRelation();
+         }
+      }).transform(new Function<Link, Optional<Object>>() {
+         @Override
+         public Optional<Object> apply(Link link) {
+            Collection<String> markers = parseQueryToMap(link.getHref().getRawQuery()).get("marker");
+            return Optional.<Object> fromNullable(markers == null ? null : Iterables.get(markers, 0));
+         }
+      }).first().or(Optional.absent());
+   }
+
+}
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/TenantApi.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/TenantApi.java
index 68a0118..8138261 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/TenantApi.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/TenantApi.java
@@ -18,11 +18,13 @@
  */
 package org.jclouds.openstack.keystone.v2_0.features;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.jclouds.collect.PagedIterable;
 import org.jclouds.concurrent.Timeout;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 
 /**
  * Provides synchronous access to the KeyStone Tenant API.
@@ -40,7 +42,9 @@
    /**
     * The operation returns a list of tenants which the current token provides access to.
     */
-   Set<? extends Tenant> list();
+   PagedIterable<? extends Tenant> list();
+
+   PaginatedCollection<? extends Tenant> list(PaginationOptions options);
 
    /**
     * Retrieve information about a tenant, by tenant ID
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/TenantAsyncApi.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/TenantAsyncApi.java
index 43b1ebe..b2476ce 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/TenantAsyncApi.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/TenantAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.keystone.v2_0.features;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -27,14 +25,22 @@
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.v2_0.functions.ReturnEmptyPaginatedCollectionOnNotFoundOr404;
+import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseTenants;
+import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseTenants.ToPagedIterable;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 import org.jclouds.openstack.v2_0.services.Identity;
 import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
 import com.google.common.util.concurrent.ListenableFuture;
@@ -57,12 +63,22 @@
     * @see TenantApi#list()
     */
    @GET
-   @SelectJson("tenants")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/tenants")
    @RequestFilters(AuthenticateRequest.class)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Tenant>> list();
+   @ResponseParser(ParseTenants.class)
+   @Transform(ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends Tenant>> list();
+
+   /** @see TenantApi#list(PaginationOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/tenants")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseTenants.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends Tenant>> list(PaginationOptions options);
 
    /** @see TenantApi#get(String) */
    @GET
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/UserApi.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/UserApi.java
index 619ecf0..ff74999 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/UserApi.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/UserApi.java
@@ -21,9 +21,12 @@
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.jclouds.collect.PagedIterable;
 import org.jclouds.concurrent.Timeout;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.domain.Role;
 import org.jclouds.openstack.keystone.v2_0.domain.User;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 
 import com.google.common.annotations.Beta;
 
@@ -48,7 +51,9 @@
     * 
     * @return the list of users
     */
-   Set<? extends User> list();
+   PagedIterable<? extends User> list();
+
+   PaginatedCollection<? extends User> list(PaginationOptions options);
 
    /**
     * Retrieve information about a user, by user ID
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/UserAsyncApi.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/UserAsyncApi.java
index d7ba6a8..f91d61f 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/UserAsyncApi.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/features/UserAsyncApi.java
@@ -27,14 +27,23 @@
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.domain.Role;
 import org.jclouds.openstack.keystone.v2_0.domain.User;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.v2_0.functions.ReturnEmptyPaginatedCollectionOnNotFoundOr404;
+import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseUsers;
+import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseUsers.ToPagedIterable;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 import org.jclouds.openstack.v2_0.services.Identity;
 import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
@@ -43,10 +52,10 @@
 /**
  * Provides asynchronous access to User via their REST API.
  * <p/>
- *
+ * 
  * @see UserApi
  * @see <a href=
- *       "http://docs.openstack.org/api/openstack-identity-service/2.0/content/User_Operations.html"
+ *      "http://docs.openstack.org/api/openstack-identity-service/2.0/content/User_Operations.html"
  *      />
  * @author Adam Lowe
  */
@@ -54,14 +63,26 @@
 @SkipEncoding({ '/', '=' })
 public interface UserAsyncApi {
 
-   /** @see UserApi#list() */
+   /**
+    * @see UserApi#list()
+    */
    @GET
-   @SelectJson("users")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/users")
    @RequestFilters(AuthenticateRequest.class)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends User>> list();
+   @ResponseParser(ParseUsers.class)
+   @Transform(ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends User>> list();
+
+   /** @see UserApi#list(PaginationOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/users")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseUsers.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends User>> list(PaginationOptions options);
 
    /** @see UserApi#get(String) */
    @GET
@@ -71,7 +92,7 @@
    @RequestFilters(AuthenticateRequest.class)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
    ListenableFuture<? extends User> get(@PathParam("userId") String userId);
-   
+
    /** @see UserApi#getByName(String) */
    @GET
    @SelectJson("user")
@@ -80,7 +101,7 @@
    @RequestFilters(AuthenticateRequest.class)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
    ListenableFuture<? extends User> getByName(@QueryParam("name") String userName);
-   
+
    /** @see UserApi#listRolesOfUser(String) */
    @GET
    @SelectJson("roles")
@@ -97,5 +118,6 @@
    @Path("/tenants/{tenantId}/users/{userId}/roles")
    @RequestFilters(AuthenticateRequest.class)
    @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Role>> listRolesOfUserOnTenant(@PathParam("userId") String userId, @PathParam("tenantId") String tenantId);
+   ListenableFuture<? extends Set<? extends Role>> listRolesOfUserOnTenant(@PathParam("userId") String userId,
+            @PathParam("tenantId") String tenantId);
 }
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/ReturnEmptyPaginatedCollectionOnNotFoundOr404.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/ReturnEmptyPaginatedCollectionOnNotFoundOr404.java
new file mode 100644
index 0000000..e454d20
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/ReturnEmptyPaginatedCollectionOnNotFoundOr404.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.keystone.v2_0.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.functions.ReturnTrueOn404;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Singleton
+public class ReturnEmptyPaginatedCollectionOnNotFoundOr404 implements Function<Exception, Object> {
+   private final ReturnTrueOn404 rto404;
+
+   @Inject
+   private ReturnEmptyPaginatedCollectionOnNotFoundOr404(ReturnTrueOn404 rto404) {
+      this.rto404 = checkNotNull(rto404, "rto404");
+   }
+
+   public Object apply(Exception from) {
+      Iterable<ResourceNotFoundException> throwables = Iterables.filter(Throwables.getCausalChain(from),
+               ResourceNotFoundException.class);
+      if (Iterables.size(throwables) >= 1) {
+         return PaginatedCollection.EMPTY;
+      } else if (rto404.apply(from)) {
+         return PaginatedCollection.EMPTY;
+      }
+      throw Throwables.propagate(from);
+   }
+
+}
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/internal/ParseTenants.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/internal/ParseTenants.java
new file mode 100644
index 0000000..bd1f867
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/internal/ParseTenants.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.keystone.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
+import org.jclouds.openstack.keystone.v2_0.features.TenantApi;
+import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseTenants.Tenants;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseTenants extends ParseJson<Tenants<? extends Tenant>> {
+   static class Tenants<T extends Tenant> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "tenants", "tenants_links" })
+      protected Tenants(Iterable<T> tenants, Iterable<Link> tenants_links) {
+         super(tenants, tenants_links);
+      }
+
+   }
+
+   @Inject
+   public ParseTenants(Json json) {
+      super(json, new TypeLiteral<Tenants<? extends Tenant>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<Tenant, ToPagedIterable> {
+
+      private final KeystoneApi api;
+
+      @Inject
+      protected ToPagedIterable(KeystoneApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<Tenant>> markerToNextForCallingArg0(final String ignored) {
+         final TenantApi tenantApi = api.getTenantApi().get();
+         return new Function<Object, IterableWithMarker<Tenant>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<Tenant> apply(Object input) {
+               return IterableWithMarker.class.cast(tenantApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "listTenants()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/internal/ParseUsers.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/internal/ParseUsers.java
new file mode 100644
index 0000000..ad4dfb3
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/keystone/v2_0/functions/internal/ParseUsers.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.keystone.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.keystone.v2_0.domain.User;
+import org.jclouds.openstack.keystone.v2_0.features.UserApi;
+import org.jclouds.openstack.keystone.v2_0.functions.internal.ParseUsers.Users;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseUsers extends ParseJson<Users<? extends User>> {
+   static class Users<T extends User> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "users", "users_links" })
+      protected Users(Iterable<T> users, Iterable<Link> users_links) {
+         super(users, users_links);
+      }
+
+   }
+
+   @Inject
+   public ParseUsers(Json json) {
+      super(json, new TypeLiteral<Users<? extends User>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<User, ToPagedIterable> {
+
+      private final KeystoneApi api;
+
+      @Inject
+      protected ToPagedIterable(KeystoneApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<User>> markerToNextForCallingArg0(final String ignored) {
+         final UserApi userApi = api.getUserApi().get();
+         return new Function<Object, IterableWithMarker<User>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<User> apply(Object input) {
+               return IterableWithMarker.class.cast(userApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "listUsers()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Link.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Link.java
index 61e45b6..e5e82ff 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Link.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/domain/Link.java
@@ -25,18 +25,17 @@
 
 import javax.inject.Named;
 
-import org.jclouds.javax.annotation.Nullable;
-
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Optional;
 
 /**
  * For convenience, resources contain links to themselves. This allows a api to easily obtain a
  * resource URIs rather than to construct them.
- *
+ * 
  * @author AdrianCole
  * @see <a href= "http://docs.openstack.org/api/openstack-compute/1.1/content/LinksReferences.html"
-/>
+ *      />
  */
 public class Link {
    /**
@@ -57,9 +56,17 @@
        */
       DESCRIBEDBY,
       /**
-       * an alternate representation of the resource. For example, an OpenStack Compute image may
-       * have an alternate representation in the OpenStack Image service.
+       * Indicates that the link's context is a part of a series, and that the next in the series is
+       * the link target.
        */
+      NEXT,
+
+      /**
+       * Indicates that the link's context is a part of a series, and that the previous in the
+       * series is the link target.
+       */
+      PREVIOUS,
+
       ALTERNATE,
       /**
        * the value returned by the OpenStack service was not recognized.
@@ -83,80 +90,67 @@
       return new Link(relation, null, href);
    }
 
-   public static Link create(Relation relation,String type, URI href) {
-      return new Link(relation, type, href);
+   public static Link create(Relation relation, String type, URI href) {
+      return new Link(relation, Optional.fromNullable(type), href);
    }
 
-   public static Builder<?> builder() {
-      return new ConcreteBuilder();
+   public static Builder builder() {
+      return new Builder();
    }
 
-   public Builder<?> toBuilder() {
-      return new ConcreteBuilder().fromLink(this);
+   public Builder toBuilder() {
+      return builder().fromLink(this);
    }
 
-   public static abstract class Builder<T extends Builder<T>>  {
-      protected abstract T self();
+   public static class Builder {
 
       protected Link.Relation relation;
-      protected String type;
+      protected Optional<String> type = Optional.absent();
       protected URI href;
 
       /**
        * @see Link#getRelation()
        */
-      public T relation(Link.Relation relation) {
+      public Builder relation(Link.Relation relation) {
          this.relation = relation;
-         return self();
+         return this;
       }
 
       /**
        * @see Link#getType()
        */
-      public T type(String type) {
-         this.type = type;
-         return self();
+      public Builder type(String type) {
+         this.type = Optional.fromNullable(type);
+         return this;
       }
 
       /**
        * @see Link#getHref()
        */
-      public T href(URI href) {
+      public Builder href(URI href) {
          this.href = href;
-         return self();
+         return this;
       }
 
       public Link build() {
          return new Link(relation, type, href);
       }
 
-      public T fromLink(Link in) {
-         return this
-               .relation(in.getRelation())
-               .type(in.getType())
-               .href(in.getHref());
-      }
-   }
-
-   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-      @Override
-      protected ConcreteBuilder self() {
-         return this;
+      public Builder fromLink(Link in) {
+         return this.relation(in.getRelation()).type(in.getType().orNull()).href(in.getHref());
       }
    }
 
    @Named("rel")
    private final Link.Relation relation;
-   private final String type;
+   private final Optional<String> type;
    private final URI href;
 
-   @ConstructorProperties({
-         "rel", "type", "href"
-   })
-   protected Link(Link.Relation relation, @Nullable String type, URI href) {
-      this.relation = checkNotNull(relation, "relation");
-      this.type = type;
+   @ConstructorProperties({ "rel", "type", "href" })
+   protected Link(Link.Relation relation, Optional<String> type, URI href) {
       this.href = checkNotNull(href, "href");
+      this.relation = checkNotNull(relation, "relation of %s", href);
+      this.type = (type == null) ? Optional.<String> absent() : type;
    }
 
    /**
@@ -167,7 +161,7 @@
     * of the resource. For example, an OpenStack Compute image may have an alternate representation
     * in the OpenStack Image service. Note that the type attribute here is used to provide a hint as
     * to the type of representation to expect when following the link.
-    *
+    * 
     * @return the relation of the resource in the current OpenStack deployment
     */
    public Link.Relation getRelation() {
@@ -177,8 +171,7 @@
    /**
     * @return the type of the resource or null if not specified
     */
-   @Nullable
-   public String getType() {
+   public Optional<String> getType() {
       return this.type;
    }
 
@@ -196,17 +189,18 @@
 
    @Override
    public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null || getClass() != obj.getClass()) return false;
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
       Link that = Link.class.cast(obj);
-      return Objects.equal(this.relation, that.relation)
-            && Objects.equal(this.type, that.type)
-            && Objects.equal(this.href, that.href);
+      return Objects.equal(this.relation, that.relation) && Objects.equal(this.type, that.type)
+               && Objects.equal(this.href, that.href);
    }
 
    protected ToStringHelper string() {
-      return Objects.toStringHelper(this)
-            .add("relation", relation).add("type", type).add("href", href);
+      return Objects.toStringHelper(this).omitNullValues().add("relation", relation).add("type", type.orNull())
+               .add("href", href);
    }
 
    @Override
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/features/ExtensionApi.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/features/ExtensionApi.java
index e8f746e..7705ca4 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/features/ExtensionApi.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/features/ExtensionApi.java
@@ -28,7 +28,7 @@
  * Provides asynchronous access to Extensions via their REST API.
  * <p/>
  * 
- * @see ExtensionApi
+ * @see ExtensionAsyncApi
  * @see <a href=
  *      "http://docs.openstack.org/api/openstack-compute/2/content/Extensions-d1e1444.html"
  *      />
@@ -42,7 +42,7 @@
     * 
     * @return all extensions
     */
-   Set<? extends Extension> listExtensions();
+   Set<? extends Extension> list();
 
    /**
     * Extensions may also be queried individually by their unique alias.
@@ -51,6 +51,6 @@
     *           id of the extension
     * @return extension or null if not found
     */
-   Extension getExtensionByAlias(String alias);
+   Extension get(String alias);
 
 }
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/features/ExtensionAsyncApi.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/features/ExtensionAsyncApi.java
index c6b957f..ef88c60 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/features/ExtensionAsyncApi.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/features/ExtensionAsyncApi.java
@@ -52,23 +52,23 @@
 public interface ExtensionAsyncApi {
 
    /**
-    * @see ExtensionApi#listExtensions
+    * @see ExtensionApi#list
     */
    @GET
    @SelectJson("extensions")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/extensions")
    @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Extension>> listExtensions();
+   ListenableFuture<? extends Set<? extends Extension>> list();
 
    /**
-    * @see ExtensionApi#getExtensionByAlias
+    * @see ExtensionApi#get
     */
    @GET
    @SelectJson("extension")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/extensions/{alias}")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends Extension> getExtensionByAlias(@PathParam("alias") String id);
+   ListenableFuture<? extends Extension> get(@PathParam("alias") String id);
 
 }
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/options/BaseListOptions.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/options/BaseListOptions.java
deleted file mode 100644
index f21f1d0..0000000
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/options/BaseListOptions.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.openstack.v2_0.options;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.util.Date;
-
-import org.jclouds.http.options.BaseHttpRequestOptions;
-
-/**
- * Options used to control paginated results (aka list commands).
- * 
- * @see <a href="http://docs.rackspacecloud.com/servers/api/cs-devguide-latest.pdf" />
- * @author Adrian Cole
- */
-public class BaseListOptions extends BaseHttpRequestOptions {
-   public static final BaseListOptions NONE = new BaseListOptions();
-
-   /**
-    * Only return objects changed since this time.
-    */
-   public BaseListOptions changesSince(Date ifModifiedSince) {
-      this.queryParameters.put("changes-since", checkNotNull(ifModifiedSince, "ifModifiedSince")
-               .getTime()
-               / 1000 + "");
-      return this;
-   }
-
-   /**
-    * Indicates where to begin listing. The list will only include objects that occur after the
-    * offset. This is convenient for pagination: To get the next page of results use the last result
-    * number of the current page + current page offset as the offset.
-    */
-   public BaseListOptions startAt(long offset) {
-      checkState(offset >= 0, "offset must be >= 0");
-      queryParameters.put("offset", Long.toString(checkNotNull(offset, "offset")));
-      return this;
-   }
-
-   /**
-    * To reduce load on the service, list operations will return a maximum of 1,000 items at a time.
-    * To navigate the collection, the parameters limit and offset can be set in the URI
-    * (e.g.?limit=0&offset=0). If an offset is given beyond the end of a list an empty list will be
-    * returned.
-    * <p/>
-    * Note that list operations never return itemNotFound (404) faults.
-    */
-   public BaseListOptions maxResults(int limit) {
-      checkState(limit >= 0, "limit must be >= 0");
-      checkState(limit <= 10000, "limit must be <= 10000");
-      queryParameters.put("limit", Integer.toString(limit));
-      return this;
-   }
-
-   public static class Builder {
-
-      /**
-       * @see BaseListOptions#startAt(long)
-       */
-      public static BaseListOptions startAt(long prefix) {
-         BaseListOptions options = new BaseListOptions();
-         return options.startAt(prefix);
-      }
-
-      /**
-       * @see BaseListOptions#maxResults
-       */
-      public static BaseListOptions maxResults(int maxKeys) {
-         BaseListOptions options = new BaseListOptions();
-         return options.maxResults(maxKeys);
-      }
-
-      /**
-       * @see BaseListOptions#changesSince(Date)
-       */
-      public static BaseListOptions changesSince(Date since) {
-         BaseListOptions options = new BaseListOptions();
-         return options.changesSince(since);
-      }
-
-   }
-}
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/options/PaginationOptions.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/options/PaginationOptions.java
new file mode 100644
index 0000000..6e68c61
--- /dev/null
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/options/PaginationOptions.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.v2_0.options;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Date;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Options used to control paginated results (aka list commands).
+ * 
+ * @see <a href=
+ *      "http://docs.openstack.org/api/openstack-compute/2/content/Paginated_Collections-d1e664.html"
+ *      />
+ * @author Adrian Cole
+ */
+public class PaginationOptions extends BaseHttpRequestOptions {
+   /**
+    * Only return objects changed since this time.
+    */
+   public PaginationOptions changesSince(Date ifModifiedSince) {
+      this.queryParameters.put("changes-since", checkNotNull(ifModifiedSince, "ifModifiedSince").getTime() / 1000 + "");
+      return this;
+   }
+
+   /**
+    * The marker parameter is the ID of the last item in the previous list. Items are sorted by
+    * create time in descending order. When a create time is not available they are sorted by ID.
+    */
+   public PaginationOptions marker(String marker) {
+      queryParameters.put("marker", checkNotNull(marker, "marker"));
+      return this;
+   }
+
+   /**
+    * To reduce load on the service, list operations will return a maximum of 1,000 items at a time.
+    * To navigate the collection, the parameters limit and offset can be set in the URI
+    * (e.g.?limit=0&offset=0). If an offset is given beyond the end of a list an empty list will be
+    * returned.
+    * <p/>
+    * Note that list operations never return itemNotFound (404) faults.
+    */
+   public PaginationOptions limit(int limit) {
+      checkState(limit >= 0, "limit must be >= 0");
+      checkState(limit <= 10000, "limit must be <= 10000");
+      queryParameters.put("limit", Integer.toString(limit));
+      return this;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see PaginationOptions#marker(String)
+       */
+      public static PaginationOptions marker(String marker) {
+         PaginationOptions options = new PaginationOptions();
+         return options.marker(marker);
+      }
+
+      /**
+       * @see PaginationOptions#limit
+       */
+      public static PaginationOptions limit(int limit) {
+         PaginationOptions options = new PaginationOptions();
+         return options.limit(limit);
+      }
+
+      /**
+       * @see PaginationOptions#changesSince(Date)
+       */
+      public static PaginationOptions changesSince(Date since) {
+         PaginationOptions options = new PaginationOptions();
+         return options.changesSince(since);
+      }
+
+   }
+}
diff --git a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/predicates/LinkPredicates.java b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/predicates/LinkPredicates.java
index dc5b125..85b8cf9 100644
--- a/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/predicates/LinkPredicates.java
+++ b/apis/openstack-keystone/src/main/java/org/jclouds/openstack/v2_0/predicates/LinkPredicates.java
@@ -91,7 +91,7 @@
       return new Predicate<Link>() {
          @Override
          public boolean apply(Link link) {
-            return type.equals(link.getType());
+            return type.equals(link.getType().orNull());
          }
 
          @Override
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/TenantApiExpectTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/TenantApiExpectTest.java
index 094d657..6d37a3d 100644
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/TenantApiExpectTest.java
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/TenantApiExpectTest.java
@@ -31,6 +31,7 @@
 import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
 import org.jclouds.openstack.keystone.v2_0.domain.Tenant;
 import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestApiExpectTest;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 import org.jclouds.rest.AuthorizationException;
 import org.testng.annotations.Test;
 
@@ -47,7 +48,10 @@
    public TenantApiExpectTest(){
       endpoint = "https://csnode.jclouds.org:35357";
    }
-   
+
+   Set<Tenant> expectedTenants = ImmutableSet.of(Tenant.builder().name("demo").id("05d1dc7af71646deba64cfc17b81bec0")
+            .build(), Tenant.builder().name("admin").id("7aa2e17ec29f44d193c48feaba0852cc").build());
+
    public void testListTenants() {
       TenantApi api = requestsSendResponses(
                keystoneAuthWithUsernameAndPassword,
@@ -56,16 +60,28 @@
                HttpResponse.builder().statusCode(200).payload(
                         payloadFromResourceWithContentType("/tenant_list.json", APPLICATION_JSON)).build())
                .getTenantApi().get();
-      Set<? extends Tenant> tenants = api.list();
+
+      assertEquals(api.list().concat().toImmutableSet(), expectedTenants);
+   }
+   
+   public void testListTenantsPage() {
+      TenantApi api = requestsSendResponses(
+               keystoneAuthWithUsernameAndPassword,
+               responseWithKeystoneAccess,
+               authenticatedGET().endpoint(endpoint + "/v2.0/tenants").build(),
+               HttpResponse.builder().statusCode(200).payload(
+                        payloadFromResourceWithContentType("/tenant_list.json", APPLICATION_JSON)).build())
+               .getTenantApi().get();
+      Set<? extends Tenant> tenants = api.list(new PaginationOptions()).toImmutableSet();
       assertNotNull(tenants);
       assertFalse(tenants.isEmpty());
 
-      Set<Tenant> expected = ImmutableSet.of(Tenant.builder().name("demo").id("05d1dc7af71646deba64cfc17b81bec0")
-               .build(), Tenant.builder().name("admin").id("7aa2e17ec29f44d193c48feaba0852cc").build());
-
-      assertEquals(tenants, expected);
+      assertEquals(tenants, expectedTenants);
    }
 
+   // this is not a compatible format of json per:
+   // http://docs.openstack.org/api/openstack-identity-service/2.0/content/Paginated_Collections-d1e325.html
+   @Test(enabled = false)
    public void testListTenantsATT() {
       TenantApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPassword,
@@ -74,15 +90,15 @@
             HttpResponse.builder().statusCode(200).payload(
                   payloadFromResourceWithContentType("/tenant_list_att.json", APPLICATION_JSON)).build())
             .getTenantApi().get();
-      Set<? extends Tenant> tenants = api.list();
-      assertNotNull(tenants);
-      assertFalse(tenants.isEmpty());
 
       Set<Tenant> expected = ImmutableSet.of(Tenant.builder().name("this-is-a-test").id("14").description("None").build());
 
-      assertEquals(tenants, expected);
+      assertEquals(api.list().concat().toImmutableSet(), expected);
    }
    
+   // this is not a compatible format of json per:
+   // http://docs.openstack.org/api/openstack-identity-service/2.0/content/Paginated_Collections-d1e325.html
+   @Test(enabled = false)
    public void testListTenantsFailNotFound() {
       TenantApi api = requestsSendResponses(keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
                authenticatedGET().endpoint(endpoint + "/v2.0/tenants").build(), HttpResponse.builder().statusCode(404).build())
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/TenantApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/TenantApiLiveTest.java
index 8c09e41..e3a4033 100644
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/TenantApiLiveTest.java
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/TenantApiLiveTest.java
@@ -38,7 +38,7 @@
 
    public void testTenants() {
       TenantApi api = keystoneContext.getApi().getTenantApi().get();
-      Set<? extends Tenant> result = api.list();
+      Set<? extends Tenant> result = api.list().concat().toImmutableSet();
       assertNotNull(result);
       assertFalse(result.isEmpty());
 
@@ -56,7 +56,7 @@
 
       TenantApi api = keystoneContext.getApi().getTenantApi().get();
 
-      for (Tenant tenant : api.list()) {
+      for (Tenant tenant : api.list().concat()) {
          Tenant aTenant = api.getByName(tenant.getName());
          assertNotNull(aTenant, "get returned null for tenant: " + tenant);
 
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/UserApiExpectTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/UserApiExpectTest.java
index 01eddef..104a96f 100644
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/UserApiExpectTest.java
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/UserApiExpectTest.java
@@ -30,9 +30,11 @@
 import org.jclouds.http.HttpResponse;
 import org.jclouds.http.HttpResponseException;
 import org.jclouds.openstack.keystone.v2_0.KeystoneApi;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.domain.Role;
 import org.jclouds.openstack.keystone.v2_0.domain.User;
 import org.jclouds.openstack.keystone.v2_0.internal.BaseKeystoneRestApiExpectTest;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 import org.jclouds.rest.AuthorizationException;
 import org.testng.annotations.Test;
 
@@ -43,31 +45,50 @@
  *
  * @author Adam Lowe
  */
-@Test(testName = "UserApiExpectTest")
+@Test(singleThreaded = true, testName = "UserApiExpectTest")
 public class UserApiExpectTest extends BaseKeystoneRestApiExpectTest<KeystoneApi> {
    
    public UserApiExpectTest(){
       endpoint = "https://csnode.jclouds.org:35357";
    }
-
+   
+   Set<User> expectedUsers = ImmutableSet.of(
+            User.builder().name("nova").id("e021dfd758eb44a89f1c57c8ef3be8e2").build(),
+            User.builder().name("glance").id("3f6c1c9ba993495ead7d2eb2192e284f").build(),
+            User.builder().name("demo").id("667b2e1420604df8b67cd8ea57d4ee64").build(),
+            User.builder().name("admin").id("2b9b606181634ae9ac86fd95a8bc2cde").build()
+      );
+   
    public void testListUsers() {
       UserApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/v2.0/users").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_list.json", APPLICATION_JSON)).build())
             .getUserApi().get();
-      Set<? extends User> users = api.list();
+     
+      assertEquals(api.list().concat().toImmutableSet(), expectedUsers);
+   }
+   
+   public void testListUsersPage() {
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint + "/v2.0/users").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/user_list.json", APPLICATION_JSON)).build())
+            .getUserApi().get();
+      PaginatedCollection<? extends User> users = api.list(new PaginationOptions());
       assertNotNull(users);
       assertFalse(users.isEmpty());
 
-      Set<User> expected = ImmutableSet.of(
-            User.builder().name("nova").id("e021dfd758eb44a89f1c57c8ef3be8e2").build(),
-            User.builder().name("glance").id("3f6c1c9ba993495ead7d2eb2192e284f").build(),
-            User.builder().name("demo").id("667b2e1420604df8b67cd8ea57d4ee64").build(),
-            User.builder().name("admin").id("2b9b606181634ae9ac86fd95a8bc2cde").build()
-      );
 
-      assertEquals(users, expected);
+      assertEquals(users.toImmutableSet(), expectedUsers);
+   }
+   
+   public void testListUsersNotFound() {
+      UserApi api = requestsSendResponses(
+            keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
+            authenticatedGET().endpoint(endpoint + "/v2.0/users").build(),
+            HttpResponse.builder().statusCode(404).build()).getUserApi().get();
+      assertEquals( api.list(new PaginationOptions()).size(), 0);
    }
 
    @Test(expectedExceptions = AuthorizationException.class)
@@ -76,7 +97,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/v2.0/users").build(),
             HttpResponse.builder().statusCode(401).build()).getUserApi().get();
-      api.list();
+      api.list(new PaginationOptions());
    }
 
    public void testGetUser() {
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/UserApiLiveTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/UserApiLiveTest.java
index 6e9759a..cfb9661 100644
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/UserApiLiveTest.java
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/keystone/v2_0/features/UserApiLiveTest.java
@@ -41,7 +41,7 @@
    public void testUsers() {
 
       UserApi api = keystoneContext.getApi().getUserApi().get();
-      Set<? extends User> users = api.list();
+      Set<? extends User> users = api.list().concat().toImmutableSet();
       assertNotNull(users);
       assertFalse(users.isEmpty());
       for (User user : users) {
@@ -54,10 +54,9 @@
    public void testUserRolesOnTenant() {
 
       UserApi api = keystoneContext.getApi().getUserApi().get();
-      Set<? extends User> users = api.list();
-      Set<? extends Tenant> tenants = keystoneContext.getApi().getTenantApi().get().list();
+      Set<? extends Tenant> tenants = keystoneContext.getApi().getTenantApi().get().list().concat().toImmutableSet();
 
-      for (User user : users) {
+      for (User user : api.list().concat()) {
          for (Tenant tenant : tenants) {
             Set<? extends Role> roles = api.listRolesOfUserOnTenant(user.getId(), tenant.getId());
             for (Role role : roles) {
@@ -71,7 +70,7 @@
    public void testListRolesOfUser() {
 
       UserApi api = keystoneContext.getApi().getUserApi().get();
-      for (User user : api.list()) {
+      for (User user : api.list().concat()) {
          Set<? extends Role> roles = api.listRolesOfUser(user.getId());
          for (Role role : roles) {
             assertNotNull(role.getId());
@@ -83,7 +82,7 @@
    public void testUsersByName() {
 
       UserApi api = keystoneContext.getApi().getUserApi().get();
-      for (User user : api.list()) {
+      for (User user : api.list().concat()) {
          User aUser = api.getByName(user.getName());
          assertEquals(aUser, user);
       }
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java
index 9fa985b..6e74370 100644
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/functions/PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSetTest.java
@@ -5,13 +5,10 @@
 import java.net.URI;
 import java.util.Set;
 
-import javax.inject.Named;
-
 import org.jclouds.date.internal.SimpleDateFormatDateService;
 import org.jclouds.internal.ClassMethodArgsAndReturnVal;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.domain.Extension;
-import org.jclouds.openstack.v2_0.functions.PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet;
 import org.jclouds.rest.annotations.Delegate;
 import org.testng.annotations.Test;
 
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/options/BaseListOptionsTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/options/BaseListOptionsTest.java
deleted file mode 100644
index 5387aec..0000000
--- a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/options/BaseListOptionsTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.openstack.v2_0.options;
-
-import static org.jclouds.openstack.v2_0.options.BaseListOptions.Builder.changesSince;
-import static org.jclouds.openstack.v2_0.options.BaseListOptions.Builder.maxResults;
-import static org.jclouds.openstack.v2_0.options.BaseListOptions.Builder.startAt;
-import static org.testng.Assert.assertEquals;
-
-import java.util.Date;
-
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Tests behavior of {@code ListOptions}
- * 
- * @author Adrian Cole
- */
-@Test(groups = "unit")
-public class BaseListOptionsTest {
-
-   public void testChangesSince() {
-      Date ifModifiedSince = new Date();
-      BaseListOptions options = new BaseListOptions().changesSince(ifModifiedSince);
-      assertEquals(ImmutableList.of(ifModifiedSince.getTime() / 1000 + ""), options
-               .buildQueryParameters().get("changes-since"));
-   }
-
-   public void testStartAt() {
-      long offset = 1;
-      BaseListOptions options = new BaseListOptions().startAt(offset);
-      assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("offset"));
-   }
-
-   public void testMaxResults() {
-      int limit = 1;
-      BaseListOptions options = new BaseListOptions().maxResults(limit);
-      assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
-   }
-
-   public void testChangesSinceStatic() {
-      Date ifModifiedSince = new Date();
-      BaseListOptions options = changesSince(ifModifiedSince);
-      assertEquals(ImmutableList.of(ifModifiedSince.getTime() / 1000 + ""), options
-               .buildQueryParameters().get("changes-since"));
-   }
-
-   public void testStartAtStatic() {
-      long offset = 1;
-      BaseListOptions options = startAt(offset);
-      assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("offset"));
-   }
-
-   public void testMaxResultsStatic() {
-      int limit = 1;
-      BaseListOptions options = maxResults(limit);
-      assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
-   }
-}
diff --git a/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/options/PaginationOptionsTest.java b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/options/PaginationOptionsTest.java
new file mode 100644
index 0000000..7e594bd
--- /dev/null
+++ b/apis/openstack-keystone/src/test/java/org/jclouds/openstack/v2_0/options/PaginationOptionsTest.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.v2_0.options;
+
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.changesSince;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.limit;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Date;
+
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Tests behavior of {@code ListOptions}
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "PaginationOptionsTest")
+public class PaginationOptionsTest {
+
+   public void testChangesSince() {
+      Date ifModifiedSince = new Date();
+      PaginationOptions options = new PaginationOptions().changesSince(ifModifiedSince);
+      assertEquals(ImmutableList.of(ifModifiedSince.getTime() / 1000 + ""),
+               options.buildQueryParameters().get("changes-since"));
+   }
+
+   public void testMarker() {
+      String marker = "52415800-8b69-11e0-9b19-734f6f006e54";
+      PaginationOptions options = new PaginationOptions().marker(marker);
+      assertEquals(ImmutableList.of(marker), options.buildQueryParameters().get("marker"));
+   }
+
+   public void testMaxResults() {
+      int limit = 1;
+      PaginationOptions options = new PaginationOptions().limit(limit);
+      assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
+   }
+
+   public void testChangesSinceStatic() {
+      Date ifModifiedSince = new Date();
+      PaginationOptions options = changesSince(ifModifiedSince);
+      assertEquals(ImmutableList.of(ifModifiedSince.getTime() / 1000 + ""),
+               options.buildQueryParameters().get("changes-since"));
+   }
+
+   public void testMarkerStatic() {
+      String marker = "52415800-8b69-11e0-9b19-734f6f006e54";
+      PaginationOptions options = marker(marker);
+      assertEquals(ImmutableList.of(marker), options.buildQueryParameters().get("marker"));
+   }
+
+   public void testMaxResultsStatic() {
+      int limit = 1;
+      PaginationOptions options = limit(limit);
+      assertEquals(ImmutableList.of("1"), options.buildQueryParameters().get("limit"));
+   }
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java
index 35eb3db..1940faf 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaApi.java
@@ -25,7 +25,7 @@
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.location.Zone;
 import org.jclouds.location.functions.ZoneToEndpoint;
-import org.jclouds.openstack.nova.v2_0.extensions.AdminActionsApi;
+import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPApi;
 import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationApi;
@@ -156,7 +156,7 @@
     * Provides synchronous access to Server Admin Actions features.
     */
    @Delegate
-   Optional<? extends AdminActionsApi> getAdminActionsExtensionForZone(
+   Optional<? extends ServerAdminApi> getServerAdminExtensionForZone(
          @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
  
    /**
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java
index 3e71a78..09631d3 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/NovaAsyncApi.java
@@ -23,7 +23,7 @@
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.location.Zone;
 import org.jclouds.location.functions.ZoneToEndpoint;
-import org.jclouds.openstack.nova.v2_0.extensions.AdminActionsAsyncApi;
+import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FloatingIPAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.HostAdministrationAsyncApi;
@@ -155,7 +155,7 @@
     * Provides asynchronous access to Server Admin Actions features.
     */
    @Delegate
-   Optional<? extends AdminActionsAsyncApi> getAdminActionsExtensionForZone(
+   Optional<? extends ServerAdminAsyncApi> getServerAdminExtensionForZone(
          @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
    /**
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/binders/BindMetadataToJsonPayload.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/binders/BindMetadataToJsonPayload.java
new file mode 100644
index 0000000..7030261
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/binders/BindMetadataToJsonPayload.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy 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.openstack.nova.v2_0.binders;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Singleton
+public class BindMetadataToJsonPayload extends BindToJsonPayload {
+
+   @Inject
+   public BindMetadataToJsonPayload(Json jsonBinder) {
+      super(jsonBinder);
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      return bindToRequest(request,
+               (Object) ImmutableMap.of("metadata", ImmutableMap.of(postParams.get("key"), postParams.get("value"))));
+   }
+}
\ No newline at end of file
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java
index 2114043..d219d72 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeService.java
@@ -21,6 +21,7 @@
 import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
 import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
 import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
+import static org.jclouds.openstack.nova.v2_0.predicates.KeyPairPredicates.nameMatches;
 
 import java.util.Map;
 import java.util.Set;
@@ -65,7 +66,6 @@
 import org.jclouds.openstack.nova.v2_0.domain.zonescoped.ZoneAndName;
 import org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi;
 import org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi;
-import org.jclouds.openstack.nova.v2_0.predicates.KeyPairPredicates;
 import org.jclouds.openstack.nova.v2_0.predicates.SecurityGroupPredicates;
 import org.jclouds.scriptbuilder.functions.InitAdminAccess;
 
@@ -138,11 +138,11 @@
       Optional<? extends SecurityGroupApi> securityGroupApi = novaApi.getSecurityGroupExtensionForZone(zoneId);
       if (securityGroupApi.isPresent()) {
          for (String group : groups) {
-            for (SecurityGroup securityGroup : Iterables.filter(securityGroupApi.get().listSecurityGroups(),
+            for (SecurityGroup securityGroup : Iterables.filter(securityGroupApi.get().list(),
                      SecurityGroupPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
                ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, securityGroup.getName());
                logger.debug(">> deleting securityGroup(%s)", zoneAndName);
-               securityGroupApi.get().deleteSecurityGroup(securityGroup.getId());
+               securityGroupApi.get().delete(securityGroup.getId());
                // TODO: test this clear happens
                securityGroupMap.invalidate(zoneAndName);
                logger.debug("<< deleted securityGroup(%s)", zoneAndName);
@@ -155,16 +155,13 @@
       Optional<? extends KeyPairApi> keyPairApi = novaApi.getKeyPairExtensionForZone(zoneId);
       if (keyPairApi.isPresent()) {
          for (String group : groups) {
-            for (Map<String, ? extends KeyPair> view : keyPairApi.get().listKeyPairs()) {
-               for (KeyPair pair : Iterables.filter(view.values(),
-                        KeyPairPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
-                  ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, pair.getName());
-                  logger.debug(">> deleting keypair(%s)", zoneAndName);
-                  keyPairApi.get().deleteKeyPair(pair.getName());
-                  // TODO: test this clear happens
-                  keyPairCache.invalidate(zoneAndName);
-                  logger.debug("<< deleted keypair(%s)", zoneAndName);
-               }
+            for (KeyPair pair : keyPairApi.get().list().filter(nameMatches(namingConvention.create().containsGroup(group)))) {
+               ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, pair.getName());
+               logger.debug(">> deleting keypair(%s)", zoneAndName);
+               keyPairApi.get().delete(pair.getName());
+               // TODO: test this clear happens
+               keyPairCache.invalidate(zoneAndName);
+               logger.debug("<< deleted keypair(%s)", zoneAndName);
             }
             keyPairCache.invalidate(ZoneAndName.fromZoneAndName(zoneId,
                      namingConvention.create().sharedNameForGroup(group)));
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
index f2b5138..f934682 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapter.java
@@ -124,8 +124,8 @@
       String flavorId = template.getHardware().getProviderId();
 
       logger.debug(">> creating new server zone(%s) name(%s) image(%s) flavor(%s) options(%s)", zoneId, name, imageId, flavorId, options);
-      ServerCreated lightweightServer = novaApi.getServerApiForZone(zoneId).createServer(name, imageId, flavorId, options);
-      Server server = novaApi.getServerApiForZone(zoneId).getServer(lightweightServer.getId());
+      ServerCreated lightweightServer = novaApi.getServerApiForZone(zoneId).create(name, imageId, flavorId, options);
+      Server server = novaApi.getServerApiForZone(zoneId).get(lightweightServer.getId());
 
       logger.trace("<< server(%s)", server.getId());
 
@@ -140,7 +140,7 @@
    public Iterable<FlavorInZone> listHardwareProfiles() {
       Builder<FlavorInZone> builder = ImmutableSet.builder();
       for (final String zoneId : zoneIds.get()) {
-         builder.addAll(transform(novaApi.getFlavorApiForZone(zoneId).listFlavorsInDetail(),
+         builder.addAll(transform(novaApi.getFlavorApiForZone(zoneId).listInDetail().concat(),
                   new Function<Flavor, FlavorInZone>() {
 
                      @Override
@@ -159,7 +159,7 @@
       Set<String> zones = zoneIds.get();
       checkState(zones.size() > 0, "no zones found in supplier %s", zoneIds);
       for (final String zoneId : zones) {
-         Set<? extends Image> images = novaApi.getImageApiForZone(zoneId).listImagesInDetail();
+         Set<? extends Image> images = novaApi.getImageApiForZone(zoneId).listInDetail().concat().toImmutableSet();
          if (images.size() == 0) {
             logger.debug("no images found in zone %s", zoneId);
             continue;
@@ -194,8 +194,8 @@
    public Iterable<ServerInZone> listNodes() {
       Builder<ServerInZone> builder = ImmutableSet.builder();
       for (final String zoneId : zoneIds.get()) {
-         builder.addAll(transform(novaApi.getServerApiForZone(zoneId).listServersInDetail(),
-                  new Function<Server, ServerInZone>() {
+         builder.addAll(novaApi.getServerApiForZone(zoneId).listInDetail().concat()
+                  .transform(new Function<Server, ServerInZone>() {
 
                      @Override
                      public ServerInZone apply(Server arg0) {
@@ -216,14 +216,14 @@
    @Override
    public ServerInZone getNode(String id) {
       ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
-      Server server = novaApi.getServerApiForZone(zoneAndId.getZone()).getServer(zoneAndId.getId());
+      Server server = novaApi.getServerApiForZone(zoneAndId.getZone()).get(zoneAndId.getId());
       return server == null ? null : new ServerInZone(server, zoneAndId.getZone());
    }
 
    @Override
    public ImageInZone getImage(String id) {
       ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
-      Image image = novaApi.getImageApiForZone(zoneAndId.getZone()).getImage(zoneAndId.getId());
+      Image image = novaApi.getImageApiForZone(zoneAndId.getZone()).get(zoneAndId.getId());
       return image == null ? null : new ImageInZone(image, zoneAndId.getZone());
    }
 
@@ -237,20 +237,20 @@
             logger.warn(e, "<< error removing and deallocating ip from node(%s): %s", id, e.getMessage());
          }
       }
-      novaApi.getServerApiForZone(zoneAndId.getZone()).deleteServer(zoneAndId.getId());
+      novaApi.getServerApiForZone(zoneAndId.getZone()).delete(zoneAndId.getId());
    }
 
    @Override
    public void rebootNode(String id) {
       ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
-      novaApi.getServerApiForZone(zoneAndId.getZone()).rebootServer(zoneAndId.getId(), RebootType.HARD);
+      novaApi.getServerApiForZone(zoneAndId.getZone()).reboot(zoneAndId.getId(), RebootType.HARD);
    }
 
    @Override
    public void resumeNode(String id) {
       ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
-      if (novaApi.getAdminActionsExtensionForZone(zoneAndId.getZone()).isPresent()) {
-         novaApi.getAdminActionsExtensionForZone(zoneAndId.getZone()).get().resumeServer(zoneAndId.getId());
+      if (novaApi.getServerAdminExtensionForZone(zoneAndId.getZone()).isPresent()) {
+         novaApi.getServerAdminExtensionForZone(zoneAndId.getZone()).get().resume(zoneAndId.getId());
       }
       throw new UnsupportedOperationException("resume requires installation of the Admin Actions extension");
    }
@@ -258,8 +258,8 @@
    @Override
    public void suspendNode(String id) {
       ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
-      if (novaApi.getAdminActionsExtensionForZone(zoneAndId.getZone()).isPresent()) {
-         novaApi.getAdminActionsExtensionForZone(zoneAndId.getZone()).get().suspendServer(zoneAndId.getId());
+      if (novaApi.getServerAdminExtensionForZone(zoneAndId.getZone()).isPresent()) {
+         novaApi.getServerAdminExtensionForZone(zoneAndId.getZone()).get().suspend(zoneAndId.getId());
       }
       throw new UnsupportedOperationException("suspend requires installation of the Admin Actions extension");
    }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaImageExtension.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaImageExtension.java
index 4e71c97..7670d54 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaImageExtension.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/extensions/NovaImageExtension.java
@@ -84,7 +84,7 @@
    @Override
    public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
       ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
-      Server server = novaApi.getServerApiForZone(zoneAndId.getZone()).getServer(zoneAndId.getId());
+      Server server = novaApi.getServerApiForZone(zoneAndId.getZone()).get(zoneAndId.getId());
       if (server == null)
          throw new NoSuchElementException("Cannot find server with id: " + zoneAndId);
       CloneImageTemplate template = new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(name).build();
@@ -119,7 +119,7 @@
    public boolean deleteImage(String id) {
       ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
       try {
-         this.novaApi.getImageApiForZone(zoneAndId.getZone()).deleteImage(zoneAndId.getId());
+         this.novaApi.getImageApiForZone(zoneAndId.getZone()).delete(zoneAndId.getId());
       } catch (Exception e) {
          return false;
       }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java
index 0e1193d..b02650d 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNode.java
@@ -82,11 +82,11 @@
       FloatingIP ip = null;
       try {
          logger.debug(">> allocating or reassigning floating ip for node(%s)", node.getId());
-         ip = floatingIpApi.allocate();
+         ip = floatingIpApi.create();
       } catch (InsufficientResourcesException e) {
          logger.trace("<< [%s] allocating a new floating ip for node(%s)", e.getMessage(), node.getId());
          logger.trace(">> searching for existing, unassigned floating ip for node(%s)", node.getId());
-         ArrayList<FloatingIP> unassignedIps = Lists.newArrayList(Iterables.filter(floatingIpApi.listFloatingIPs(),
+         ArrayList<FloatingIP> unassignedIps = Lists.newArrayList(Iterables.filter(floatingIpApi.list(),
                   new Predicate<FloatingIP>() {
 
                      @Override
@@ -101,7 +101,7 @@
       }
       logger.debug(">> adding floatingIp(%s) to node(%s)", ip.getIp(), node.getId());
 
-      floatingIpApi.addFloatingIPToServer(ip.getIp(), node.getProviderId());
+      floatingIpApi.addToServer(ip.getIp(), node.getProviderId());
       input.set(NodeMetadataBuilder.fromNodeMetadata(node).publicAddresses(ImmutableSet.of(ip.getIp())).build());
       floatingIpCache.invalidate(ZoneAndId.fromSlashEncoded(node.getId()));
       return input;
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java
index fb9aeb8..0150851 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/CreateSecurityGroupIfNeeded.java
@@ -67,17 +67,17 @@
       logger.debug(">> creating securityGroup %s", zoneSecurityGroupNameAndPorts);
       try {
 
-         SecurityGroup securityGroup = api.get().createSecurityGroupWithNameAndDescription(
+         SecurityGroup securityGroup = api.get().createWithDescription(
                   zoneSecurityGroupNameAndPorts.getName(), zoneSecurityGroupNameAndPorts.getName());
 
          logger.debug("<< created securityGroup(%s)", securityGroup);
          for (int port : zoneSecurityGroupNameAndPorts.getPorts()) {
             authorizeGroupToItselfAndAllIPsToTCPPort(api.get(), securityGroup, port);
          }
-         return new SecurityGroupInZone(api.get().getSecurityGroup(securityGroup.getId()), zoneId);
+         return new SecurityGroupInZone(api.get().get(securityGroup.getId()), zoneId);
       } catch (IllegalStateException e) {
          logger.trace("<< trying to find securityGroup(%s): %s", zoneSecurityGroupNameAndPorts, e.getMessage());
-         SecurityGroup group = find(api.get().listSecurityGroups(), nameEquals(zoneSecurityGroupNameAndPorts
+         SecurityGroup group = find(api.get().list(), nameEquals(zoneSecurityGroupNameAndPorts
                   .getName()));
          logger.debug("<< reused securityGroup(%s)", group.getId());
          return new SecurityGroupInZone(group, zoneId);
@@ -88,7 +88,7 @@
             SecurityGroup securityGroup, int port) {
       // NOTE that permission to itself isn't supported on trystack!
       logger.debug(">> authorizing securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, port);
-      securityGroupApi.createSecurityGroupRuleAllowingCidrBlock(securityGroup.getId(), Ingress.builder().ipProtocol(
+      securityGroupApi.createRuleAllowingCidrBlock(securityGroup.getId(), Ingress.builder().ipProtocol(
                IpProtocol.TCP).fromPort(port).toPort(port).build(), "0.0.0.0/0");
       logger.debug("<< authorized securityGroup(%s) permission to 0.0.0.0/0 on port %d", securityGroup, port);
 
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java
index 00f93cb..5a81b49 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/functions/RemoveFloatingIpFromNodeAndDeallocate.java
@@ -61,9 +61,9 @@
       FloatingIPApi floatingIpApi = novaApi.getFloatingIPExtensionForZone(id.getZone()).get();
       for (FloatingIP ip : floatingIpCache.getUnchecked(id)) {
          logger.debug(">> removing floatingIp(%s) from node(%s)", ip, id);
-         floatingIpApi.removeFloatingIPFromServer(ip.getIp(), id.getId());
+         floatingIpApi.removeFromServer(ip.getIp(), id.getId());
          logger.debug(">> deallocating floatingIp(%s)", ip);
-         floatingIpApi.deallocate(ip.getId());
+         floatingIpApi.delete(ip.getId());
       }
       floatingIpCache.invalidate(id);
       return id;
@@ -71,6 +71,6 @@
 
    @Override
    public String toString() {
-      return Objects.toStringHelper("RemoveFloatingIpFromNodeAndDeallocate").toString();
+      return Objects.toStringHelper("RemoveFloatingIpFromNodeAndDecreate").toString();
    }
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
index 6454419..7fa631a 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPair.java
@@ -68,7 +68,7 @@
       KeyPair keyPair = null;
       while (keyPair == null) {
          try {
-            keyPair = api.get().createKeyPair(namingConvention.createWithoutPrefix().uniqueNameForGroup(prefix));
+            keyPair = api.get().create(namingConvention.createWithoutPrefix().uniqueNameForGroup(prefix));
          } catch (IllegalStateException e) {
 
          }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java
index d773bd5..0a8ebb8 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstance.java
@@ -30,7 +30,6 @@
 import com.google.common.base.Predicate;
 import com.google.common.cache.CacheLoader;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 
 /**
  * Each zone may or may not have the floating ip function present. In order to safely proceed, we
@@ -53,7 +52,7 @@
       String zone = key.getZone();
       Optional<? extends FloatingIPApi> ipApiOptional = api.getFloatingIPExtensionForZone(zone);
       if (ipApiOptional.isPresent()) {
-         return Iterables.filter(ipApiOptional.get().listFloatingIPs(),
+         return ipApiOptional.get().list().filter(
                   new Predicate<FloatingIP>() {
                      @Override
                      public boolean apply(FloatingIP input) {
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
index 4de15d5..32aa332 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/options/NovaTemplateOptions.java
@@ -162,7 +162,7 @@
    /**
     * <h3>Note</h3>
     * 
-    * This requires that {@link NovaApi#getFloatingIPExtensionForZone(String)} to return
+    * This requires that {@link NovaApi#getExtensionForZone(String)} to return
     * {@link Optional#isPresent present}
     * 
     * @return true if auto assignment of a floating ip to each vm is enabled
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/GetImageWhenImageInZoneHasActiveStatusPredicateWithResult.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/GetImageWhenImageInZoneHasActiveStatusPredicateWithResult.java
index 5f2f38d..254b405 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/GetImageWhenImageInZoneHasActiveStatusPredicateWithResult.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/predicates/GetImageWhenImageInZoneHasActiveStatusPredicateWithResult.java
@@ -35,7 +35,6 @@
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
 
 /**
  * @author David Alves
@@ -89,7 +88,7 @@
    }
 
    public org.jclouds.openstack.nova.v2_0.domain.Image findImage(final ZoneAndId zoneAndId) {
-      return Iterables.tryFind(api.getImageApiForZone(zoneAndId.getZone()).listImagesInDetail(),
+      return api.getImageApiForZone(zoneAndId.getZone()).listInDetail().concat().firstMatch(
                new Predicate<org.jclouds.openstack.nova.v2_0.domain.Image>() {
                   @Override
                   public boolean apply(org.jclouds.openstack.nova.v2_0.domain.Image input) {
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
index 4958740..dbb1841 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/compute/strategy/ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.java
@@ -65,7 +65,7 @@
 public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet extends
          CreateNodesWithGroupEncodedIntoNameThenAddToSet {
 
-   private final AllocateAndAddFloatingIpToNode allocateAndAddFloatingIpToNode;
+   private final AllocateAndAddFloatingIpToNode createAndAddFloatingIpToNode;
    private final LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache;
    private final LoadingCache<ZoneAndName, KeyPair> keyPairCache;
    private final NovaApi novaApi;
@@ -77,15 +77,15 @@
             GroupNamingConvention.Factory namingConvention,
             CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
             @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
-            AllocateAndAddFloatingIpToNode allocateAndAddFloatingIpToNode,
+            AllocateAndAddFloatingIpToNode createAndAddFloatingIpToNode,
             LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache,
             LoadingCache<ZoneAndName, KeyPair> keyPairCache, NovaApi novaApi) {
       super(addNodeWithTagStrategy, listNodesStrategy, namingConvention, executor,
                customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
       this.securityGroupCache = checkNotNull(securityGroupCache, "securityGroupCache");
       this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
-      this.allocateAndAddFloatingIpToNode = checkNotNull(allocateAndAddFloatingIpToNode,
-               "allocateAndAddFloatingIpToNode");
+      this.createAndAddFloatingIpToNode = checkNotNull(createAndAddFloatingIpToNode,
+               "createAndAddFloatingIpToNode");
       this.novaApi = checkNotNull(novaApi, "novaApi");
    }
 
@@ -153,7 +153,7 @@
       NovaTemplateOptions templateOptions = NovaTemplateOptions.class.cast(template.getOptions());
 
       if (templateOptions.shouldAutoAssignFloatingIp()) {
-         return Futures.compose(future, allocateAndAddFloatingIpToNode, executor);
+         return Futures.compose(future, createAndAddFloatingIpToNode, executor);
       } else {
          return future;
       }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaProperties.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaProperties.java
index e8548ca..3275b62 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaProperties.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaProperties.java
@@ -31,10 +31,10 @@
    public static final String TIMEOUT_SECURITYGROUP_PRESENT = "jclouds.openstack-nova.timeout.securitygroup-present";
 
    /**
-    * Whenever a node is created, automatically allocate and assign a floating ip address, also
-    * deallocate when the node is destroyed.
+    * Whenever a node is created, automatically create and assign a floating ip address, also
+    * delete when the node is destroyed.
     */
-   public static final String AUTO_ALLOCATE_FLOATING_IPS = "jclouds.openstack-nova.auto-allocate-floating-ips";
+   public static final String AUTO_ALLOCATE_FLOATING_IPS = "jclouds.openstack-nova.auto-create-floating-ips";
 
    /**
     * Whenever a node is created, automatically generate keypairs for groups, as needed, also
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java
index 0bef089..597451d 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/config/NovaRestClientModule.java
@@ -32,8 +32,8 @@
 import org.jclouds.http.annotation.ServerError;
 import org.jclouds.openstack.nova.v2_0.NovaApi;
 import org.jclouds.openstack.nova.v2_0.NovaAsyncApi;
-import org.jclouds.openstack.nova.v2_0.extensions.AdminActionsApi;
-import org.jclouds.openstack.nova.v2_0.extensions.AdminActionsAsyncApi;
+import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminApi;
+import org.jclouds.openstack.nova.v2_0.extensions.ServerAdminAsyncApi;
 import org.jclouds.openstack.nova.v2_0.extensions.ExtensionNamespaces;
 import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsApi;
 import org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi;
@@ -106,7 +106,7 @@
          .put(VolumeApi.class, VolumeAsyncApi.class)
          .put(VirtualInterfaceApi.class, VirtualInterfaceAsyncApi.class)
          .put(ServerWithSecurityGroupsApi.class, ServerWithSecurityGroupsAsyncApi.class)
-         .put(AdminActionsApi.class, AdminActionsAsyncApi.class)
+         .put(ServerAdminApi.class, ServerAdminAsyncApi.class)
          .put(HostAggregateApi.class, HostAggregateAsyncApi.class)
          .put(FlavorExtraSpecsApi.class, FlavorExtraSpecsAsyncApi.class)
          .put(QuotaApi.class, QuotaAsyncApi.class)
@@ -114,6 +114,7 @@
          .put(VolumeTypeApi.class, VolumeTypeAsyncApi.class)
          .build();
    
+   @SuppressWarnings("unchecked")
    public NovaRestClientModule() {
       super(TypeToken.class.cast(TypeToken.of(NovaApi.class)), TypeToken.class.cast(TypeToken.of(NovaAsyncApi.class)), DELEGATE_MAP);
    }
@@ -172,7 +173,7 @@
             .build(new CacheLoader<String, Set<? extends Extension>>() {
                @Override
                public Set<? extends Extension> load(String key) throws Exception {
-                  return novaApi.get().getExtensionApiForZone(key).listExtensions();
+                  return novaApi.get().getExtensionApiForZone(key).list();
                }
             });
    }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Flavor.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Flavor.java
index 98137e4..80e09bd 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Flavor.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Flavor.java
@@ -36,7 +36,7 @@
  * 
  * @author Jeremy Daggett
  * @see <a href=
-      "http://docs.openstack.org/api/openstack-compute/1.1/content/Flavors-d1e4180.html"
+      "http://docs.openstack.org/api/openstack-compute/2/content/List_Flavors-d1e4188.html"
       />
 */
 public class Flavor extends Resource {
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Quota.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Quota.java
new file mode 100644
index 0000000..f52c137
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Quota.java
@@ -0,0 +1,358 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Named;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * Represents the set of limits (quotas) returned by the Quota Extension
+ * 
+ * @see org.jclouds.openstack.nova.v2_0.extensions.QuotaApi
+*/
+public class Quota {
+
+   public static Builder<?> builder() { 
+      return new ConcreteBuilder();
+   }
+   
+   public Builder<?> toBuilder() { 
+      return new ConcreteBuilder().fromQuotas(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>>  {
+      protected abstract T self();
+
+      protected String id;
+      protected int metadataItems;
+      protected int injectedFileContentBytes;
+      protected int volumes;
+      protected int gigabytes;
+      protected int ram;
+      protected int floatingIps;
+      protected int instances;
+      protected int injectedFiles;
+      protected int cores;
+      protected int securityGroups;
+      protected int securityGroupRules;
+      protected int keyPairs;
+   
+      /** 
+       * @see Quota#getId()
+       */
+      public T id(String id) {
+         this.id = id;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getMetadatas()
+       */
+      public T metadataItems(int metadataItems) {
+         this.metadataItems = metadataItems;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getInjectedFileContentBytes()
+       */
+      public T injectedFileContentBytes(int injectedFileContentBytes) {
+         this.injectedFileContentBytes = injectedFileContentBytes;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getVolumes()
+       */
+      public T volumes(int volumes) {
+         this.volumes = volumes;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getGigabytes()
+       */
+      public T gigabytes(int gigabytes) {
+         this.gigabytes = gigabytes;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getRam()
+       */
+      public T ram(int ram) {
+         this.ram = ram;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getFloatingIps()
+       */
+      public T floatingIps(int floatingIps) {
+         this.floatingIps = floatingIps;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getInstances()
+       */
+      public T instances(int instances) {
+         this.instances = instances;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getInjectedFiles()
+       */
+      public T injectedFiles(int injectedFiles) {
+         this.injectedFiles = injectedFiles;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getCores()
+       */
+      public T cores(int cores) {
+         this.cores = cores;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getSecurityGroups()
+       */
+      public T securityGroups(int securityGroups) {
+         this.securityGroups = securityGroups;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getSecurityGroupRules()
+       */
+      public T securityGroupRules(int securityGroupRules) {
+         this.securityGroupRules = securityGroupRules;
+         return self();
+      }
+
+      /** 
+       * @see Quota#getKeyPairs()
+       */
+      public T keyPairs(int keyPairs) {
+         this.keyPairs = keyPairs;
+         return self();
+      }
+
+      public Quota build() {
+         return new Quota(id, metadataItems, injectedFileContentBytes, volumes, gigabytes, ram, floatingIps, instances, injectedFiles, cores, securityGroups, securityGroupRules, keyPairs);
+      }
+      
+      public T fromQuotas(Quota in) {
+         return this
+                  .id(in.getId())
+                  .metadataItems(in.getMetadatas())
+                  .injectedFileContentBytes(in.getInjectedFileContentBytes())
+                  .volumes(in.getVolumes())
+                  .gigabytes(in.getGigabytes())
+                  .ram(in.getRam())
+                  .floatingIps(in.getFloatingIps())
+                  .instances(in.getInstances())
+                  .injectedFiles(in.getInjectedFiles())
+                  .cores(in.getCores())
+                  .securityGroups(in.getSecurityGroups())
+                  .securityGroupRules(in.getSecurityGroupRules())
+                  .keyPairs(in.getKeyPairs());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final String id;
+   @Named("metadata_items")
+   private final int metadataItems;
+   @Named("injected_file_content_bytes")
+   private final int injectedFileContentBytes;
+   private final int volumes;
+   private final int gigabytes;
+   private final int ram;
+   @Named("floating_ips")
+   private final int floatingIps;
+   private final int instances;
+   @Named("injected_files")
+   private final int injectedFiles;
+   private final int cores;
+   @Named("security_groups")
+   private final int securityGroups;
+   @Named("security_group_rules")
+   private final int securityGroupRules;
+   @Named("key_pairs")
+   private final int keyPairs;
+
+   @ConstructorProperties({
+      "id", "metadata_items", "injected_file_content_bytes", "volumes", "gigabytes", "ram", "floating_ips", "instances", "injected_files", "cores", "security_groups", "security_group_rules", "key_pairs"
+   })
+   protected Quota(String id, int metadataItems, int injectedFileContentBytes, int volumes, int gigabytes, int ram, int floatingIps, int instances, int injectedFiles, int cores, int securityGroups, int securityGroupRules, int keyPairs) {
+      this.id = checkNotNull(id, "id");
+      this.metadataItems = metadataItems;
+      this.injectedFileContentBytes = injectedFileContentBytes;
+      this.volumes = volumes;
+      this.gigabytes = gigabytes;
+      this.ram = ram;
+      this.floatingIps = floatingIps;
+      this.instances = instances;
+      this.injectedFiles = injectedFiles;
+      this.cores = cores;
+      this.securityGroups = securityGroups;
+      this.securityGroupRules = securityGroupRules;
+      this.keyPairs = keyPairs;
+   }
+
+   /**
+    * The id of the tenant this set of limits applies to
+    */
+   public String getId() {
+      return this.id;
+   }
+
+   /**
+    * The limit of the number of metadata items for the tenant
+    */
+   public int getMetadatas() {
+      return this.metadataItems;
+   }
+
+   public int getInjectedFileContentBytes() {
+      return this.injectedFileContentBytes;
+   }
+
+   /**
+    * The limit of the number of volumes that can be created for the tenant
+    */
+   public int getVolumes() {
+      return this.volumes;
+   }
+
+   /**
+    * The limit of the total size of all volumes for the tenant
+    */
+   public int getGigabytes() {
+      return this.gigabytes;
+   }
+
+   /**
+    * The limit of total ram available to the tenant
+    */
+   public int getRam() {
+      return this.ram;
+   }
+
+   /**
+    * The limit of the number of floating ips for the tenant
+    */
+   public int getFloatingIps() {
+      return this.floatingIps;
+   }
+
+   /**
+    * The limit of the number of instances that can be created for the tenant
+    */
+   public int getInstances() {
+      return this.instances;
+   }
+
+   public int getInjectedFiles() {
+      return this.injectedFiles;
+   }
+
+   /**
+    * The limit of the number of cores that can be used by the tenant
+    */
+   public int getCores() {
+      return this.cores;
+   }
+
+   /**
+    * @return the limit of the number of security groups that can be created for the tenant
+    * @see org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi
+    */
+   public int getSecurityGroups() {
+      return this.securityGroups;
+   }
+
+   /**
+    * @return the limit of the number of security group rules that can be created for the tenant
+    * @see org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi
+    */
+   public int getSecurityGroupRules() {
+      return this.securityGroupRules;
+   }
+
+   /**
+    * @return the limit of the number of key pairs that can be created for the tenant
+    * @see org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi
+    */
+   public int getKeyPairs() {
+      return this.keyPairs;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id, metadataItems, injectedFileContentBytes, volumes, gigabytes, ram, floatingIps, instances, injectedFiles, cores, securityGroups, securityGroupRules, keyPairs);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      Quota that = Quota.class.cast(obj);
+      return Objects.equal(this.id, that.id)
+               && Objects.equal(this.metadataItems, that.metadataItems)
+               && Objects.equal(this.injectedFileContentBytes, that.injectedFileContentBytes)
+               && Objects.equal(this.volumes, that.volumes)
+               && Objects.equal(this.gigabytes, that.gigabytes)
+               && Objects.equal(this.ram, that.ram)
+               && Objects.equal(this.floatingIps, that.floatingIps)
+               && Objects.equal(this.instances, that.instances)
+               && Objects.equal(this.injectedFiles, that.injectedFiles)
+               && Objects.equal(this.cores, that.cores)
+               && Objects.equal(this.securityGroups, that.securityGroups)
+               && Objects.equal(this.securityGroupRules, that.securityGroupRules)
+               && Objects.equal(this.keyPairs, that.keyPairs);
+   }
+   
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this)
+            .add("id", id).add("metadataItems", metadataItems).add("injectedFileContentBytes", injectedFileContentBytes).add("volumes", volumes).add("gigabytes", gigabytes).add("ram", ram).add("floatingIps", floatingIps).add("instances", instances).add("injectedFiles", injectedFiles).add("cores", cores).add("securityGroups", securityGroups).add("securityGroupRules", securityGroupRules).add("keyPairs", keyPairs);
+   }
+   
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/QuotaClass.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/QuotaClass.java
index 792805d..0c96b81 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/QuotaClass.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/QuotaClass.java
@@ -25,7 +25,7 @@
  * 
  * @see org.jclouds.openstack.nova.v2_0.extensions.QuotaClassApi
 */
-public class QuotaClass extends Quotas {
+public class QuotaClass extends Quota {
 
    public static Builder<?> builder() { 
       return new ConcreteBuilder();
@@ -35,7 +35,7 @@
       return new ConcreteBuilder().fromQuotaClass(this);
    }
 
-   public static abstract class Builder<T extends Builder<T>> extends Quotas.Builder<T>  {
+   public static abstract class Builder<T extends Builder<T>> extends Quota.Builder<T>  {
    
       public QuotaClass build() {
          return new QuotaClass(id, metadataItems, injectedFileContentBytes, volumes, gigabytes, ram, floatingIps, instances, injectedFiles, cores, securityGroups, securityGroupRules, keyPairs);
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Quotas.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Quotas.java
deleted file mode 100644
index 3b0d518..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/domain/Quotas.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.openstack.nova.v2_0.domain;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.beans.ConstructorProperties;
-
-import javax.inject.Named;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * Represents the set of limits (quotas) returned by the Quota Extension
- * 
- * @see org.jclouds.openstack.nova.v2_0.extensions.QuotaApi
-*/
-public class Quotas {
-
-   public static Builder<?> builder() { 
-      return new ConcreteBuilder();
-   }
-   
-   public Builder<?> toBuilder() { 
-      return new ConcreteBuilder().fromQuotas(this);
-   }
-
-   public static abstract class Builder<T extends Builder<T>>  {
-      protected abstract T self();
-
-      protected String id;
-      protected int metadataItems;
-      protected int injectedFileContentBytes;
-      protected int volumes;
-      protected int gigabytes;
-      protected int ram;
-      protected int floatingIps;
-      protected int instances;
-      protected int injectedFiles;
-      protected int cores;
-      protected int securityGroups;
-      protected int securityGroupRules;
-      protected int keyPairs;
-   
-      /** 
-       * @see Quotas#getId()
-       */
-      public T id(String id) {
-         this.id = id;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getMetadataItems()
-       */
-      public T metadataItems(int metadataItems) {
-         this.metadataItems = metadataItems;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getInjectedFileContentBytes()
-       */
-      public T injectedFileContentBytes(int injectedFileContentBytes) {
-         this.injectedFileContentBytes = injectedFileContentBytes;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getVolumes()
-       */
-      public T volumes(int volumes) {
-         this.volumes = volumes;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getGigabytes()
-       */
-      public T gigabytes(int gigabytes) {
-         this.gigabytes = gigabytes;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getRam()
-       */
-      public T ram(int ram) {
-         this.ram = ram;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getFloatingIps()
-       */
-      public T floatingIps(int floatingIps) {
-         this.floatingIps = floatingIps;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getInstances()
-       */
-      public T instances(int instances) {
-         this.instances = instances;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getInjectedFiles()
-       */
-      public T injectedFiles(int injectedFiles) {
-         this.injectedFiles = injectedFiles;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getCores()
-       */
-      public T cores(int cores) {
-         this.cores = cores;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getSecurityGroups()
-       */
-      public T securityGroups(int securityGroups) {
-         this.securityGroups = securityGroups;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getSecurityGroupRules()
-       */
-      public T securityGroupRules(int securityGroupRules) {
-         this.securityGroupRules = securityGroupRules;
-         return self();
-      }
-
-      /** 
-       * @see Quotas#getKeyPairs()
-       */
-      public T keyPairs(int keyPairs) {
-         this.keyPairs = keyPairs;
-         return self();
-      }
-
-      public Quotas build() {
-         return new Quotas(id, metadataItems, injectedFileContentBytes, volumes, gigabytes, ram, floatingIps, instances, injectedFiles, cores, securityGroups, securityGroupRules, keyPairs);
-      }
-      
-      public T fromQuotas(Quotas in) {
-         return this
-                  .id(in.getId())
-                  .metadataItems(in.getMetadataItems())
-                  .injectedFileContentBytes(in.getInjectedFileContentBytes())
-                  .volumes(in.getVolumes())
-                  .gigabytes(in.getGigabytes())
-                  .ram(in.getRam())
-                  .floatingIps(in.getFloatingIps())
-                  .instances(in.getInstances())
-                  .injectedFiles(in.getInjectedFiles())
-                  .cores(in.getCores())
-                  .securityGroups(in.getSecurityGroups())
-                  .securityGroupRules(in.getSecurityGroupRules())
-                  .keyPairs(in.getKeyPairs());
-      }
-   }
-
-   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-      @Override
-      protected ConcreteBuilder self() {
-         return this;
-      }
-   }
-
-   private final String id;
-   @Named("metadata_items")
-   private final int metadataItems;
-   @Named("injected_file_content_bytes")
-   private final int injectedFileContentBytes;
-   private final int volumes;
-   private final int gigabytes;
-   private final int ram;
-   @Named("floating_ips")
-   private final int floatingIps;
-   private final int instances;
-   @Named("injected_files")
-   private final int injectedFiles;
-   private final int cores;
-   @Named("security_groups")
-   private final int securityGroups;
-   @Named("security_group_rules")
-   private final int securityGroupRules;
-   @Named("key_pairs")
-   private final int keyPairs;
-
-   @ConstructorProperties({
-      "id", "metadata_items", "injected_file_content_bytes", "volumes", "gigabytes", "ram", "floating_ips", "instances", "injected_files", "cores", "security_groups", "security_group_rules", "key_pairs"
-   })
-   protected Quotas(String id, int metadataItems, int injectedFileContentBytes, int volumes, int gigabytes, int ram, int floatingIps, int instances, int injectedFiles, int cores, int securityGroups, int securityGroupRules, int keyPairs) {
-      this.id = checkNotNull(id, "id");
-      this.metadataItems = metadataItems;
-      this.injectedFileContentBytes = injectedFileContentBytes;
-      this.volumes = volumes;
-      this.gigabytes = gigabytes;
-      this.ram = ram;
-      this.floatingIps = floatingIps;
-      this.instances = instances;
-      this.injectedFiles = injectedFiles;
-      this.cores = cores;
-      this.securityGroups = securityGroups;
-      this.securityGroupRules = securityGroupRules;
-      this.keyPairs = keyPairs;
-   }
-
-   /**
-    * The id of the tenant this set of limits applies to
-    */
-   public String getId() {
-      return this.id;
-   }
-
-   /**
-    * The limit of the number of metadata items for the tenant
-    */
-   public int getMetadataItems() {
-      return this.metadataItems;
-   }
-
-   public int getInjectedFileContentBytes() {
-      return this.injectedFileContentBytes;
-   }
-
-   /**
-    * The limit of the number of volumes that can be created for the tenant
-    */
-   public int getVolumes() {
-      return this.volumes;
-   }
-
-   /**
-    * The limit of the total size of all volumes for the tenant
-    */
-   public int getGigabytes() {
-      return this.gigabytes;
-   }
-
-   /**
-    * The limit of total ram available to the tenant
-    */
-   public int getRam() {
-      return this.ram;
-   }
-
-   /**
-    * The limit of the number of floating ips for the tenant
-    */
-   public int getFloatingIps() {
-      return this.floatingIps;
-   }
-
-   /**
-    * The limit of the number of instances that can be created for the tenant
-    */
-   public int getInstances() {
-      return this.instances;
-   }
-
-   public int getInjectedFiles() {
-      return this.injectedFiles;
-   }
-
-   /**
-    * The limit of the number of cores that can be used by the tenant
-    */
-   public int getCores() {
-      return this.cores;
-   }
-
-   /**
-    * @return the limit of the number of security groups that can be created for the tenant
-    * @see org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi
-    */
-   public int getSecurityGroups() {
-      return this.securityGroups;
-   }
-
-   /**
-    * @return the limit of the number of security group rules that can be created for the tenant
-    * @see org.jclouds.openstack.nova.v2_0.extensions.SecurityGroupApi
-    */
-   public int getSecurityGroupRules() {
-      return this.securityGroupRules;
-   }
-
-   /**
-    * @return the limit of the number of key pairs that can be created for the tenant
-    * @see org.jclouds.openstack.nova.v2_0.extensions.KeyPairApi
-    */
-   public int getKeyPairs() {
-      return this.keyPairs;
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(id, metadataItems, injectedFileContentBytes, volumes, gigabytes, ram, floatingIps, instances, injectedFiles, cores, securityGroups, securityGroupRules, keyPairs);
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null || getClass() != obj.getClass()) return false;
-      Quotas that = Quotas.class.cast(obj);
-      return Objects.equal(this.id, that.id)
-               && Objects.equal(this.metadataItems, that.metadataItems)
-               && Objects.equal(this.injectedFileContentBytes, that.injectedFileContentBytes)
-               && Objects.equal(this.volumes, that.volumes)
-               && Objects.equal(this.gigabytes, that.gigabytes)
-               && Objects.equal(this.ram, that.ram)
-               && Objects.equal(this.floatingIps, that.floatingIps)
-               && Objects.equal(this.instances, that.instances)
-               && Objects.equal(this.injectedFiles, that.injectedFiles)
-               && Objects.equal(this.cores, that.cores)
-               && Objects.equal(this.securityGroups, that.securityGroups)
-               && Objects.equal(this.securityGroupRules, that.securityGroupRules)
-               && Objects.equal(this.keyPairs, that.keyPairs);
-   }
-   
-   protected ToStringHelper string() {
-      return Objects.toStringHelper(this)
-            .add("id", id).add("metadataItems", metadataItems).add("injectedFileContentBytes", injectedFileContentBytes).add("volumes", volumes).add("gigabytes", gigabytes).add("ram", ram).add("floatingIps", floatingIps).add("instances", instances).add("injectedFiles", injectedFiles).add("cores", cores).add("securityGroups", securityGroups).add("securityGroupRules", securityGroupRules).add("keyPairs", keyPairs);
-   }
-   
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApi.java
deleted file mode 100644
index aa2e92a..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApi.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.openstack.nova.v2_0.extensions;
-
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.openstack.nova.v2_0.domain.BackupType;
-import org.jclouds.openstack.nova.v2_0.options.CreateBackupOfServerOptions;
-import org.jclouds.openstack.v2_0.ServiceType;
-import org.jclouds.openstack.v2_0.services.Extension;
-
-/**
- * Provide additional actions for servers:
- * 'suspend', 'resume', 'migrate', 'lock', 'unlock', 'resetNetwork', 'createBackup', 'pause', 'migrateLive',
- * 'injectNetworkInfo', 'unpause'
- *
- * @author Adam Lowe
- * @see org.jclouds.openstack.nova.v2_0.extensions.AdminActionsAsyncApi
- */
-@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS)
-@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
-public interface AdminActionsApi {
-
-   /**
-    * Suspend a server.
-    *
-    * @param id id of the server
-    */
-   Boolean suspendServer(String id);
-
-   /**
-    * Resume a server.
-    *
-    * @param id id of the server
-    */
-   Boolean resumeServer(String id);
-
-   /**
-    * Migrate a server.
-    *
-    * @param id id of the server
-    */
-   Boolean migrateServer(String id);
-
-   /**
-    * Lock a server.
-    *
-    * @param id id of the server
-    */
-   Boolean lockServer(String id);
-
-   /**
-    * Unlock a server.
-    *
-    * @param id id of the server
-    */
-   Boolean unlockServer(String id);
-
-   /**
-    * Reset network of a server.
-    *
-    * @param id id of the server
-    */
-   Boolean resetNetworkOfServer(String id);
-
-   /**
-    * Create backup of a server.
-    *
-    * @param id         id of the server
-    * @param imageName  the name of the image to create
-    * @param backupType the type of backup
-    * @param rotation   the number of images to retain (0 to simply overwrite)
-    * @param options    optional rotation and/or metadata parameters
-    * @return the id of the newly created image
-    */
-   String createBackupOfServer(String id, String imageName, BackupType backupType, int rotation, CreateBackupOfServerOptions... options);
-
-   /**
-    * Pause a server.
-    *
-    * @param id id of the server
-    */
-   Boolean pauseServer(String id);
-
-   /**
-    * Unpause a server.
-    *
-    * @param id id of the server
-    */
-   Boolean unpauseServer(String id);
-
-
-   /**
-    * Live migrate a server.
-    *
-    * @param id id of the server
-    */
-   Boolean liveMigrateServer(String id, String host, boolean blockMigration, boolean diskOverCommit);
-
-   /**
-    * Inject network info into a server.
-    *
-    * @param id id of the server
-    */
-   Boolean injectNetworkInfoIntoServer(String id);
-}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsAsyncApi.java
deleted file mode 100644
index a219e21..0000000
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsAsyncApi.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.openstack.nova.v2_0.extensions;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
-import org.jclouds.openstack.nova.v2_0.domain.BackupType;
-import org.jclouds.openstack.nova.v2_0.functions.ParseImageIdFromLocationHeader;
-import org.jclouds.openstack.nova.v2_0.options.CreateBackupOfServerOptions;
-import org.jclouds.openstack.v2_0.ServiceType;
-import org.jclouds.openstack.v2_0.services.Extension;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.Payload;
-import org.jclouds.rest.annotations.PayloadParam;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.annotations.WrapWith;
-import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
-import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provide access to Admin Server Actions via REST API
- *
- * @author Adam Lowe
- * @see org.jclouds.openstack.nova.v2_0.extensions.AdminActionsApi
- */
-@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS)
-@SkipEncoding( { '/', '=' })
-@RequestFilters(AuthenticateRequest.class)
-@Path("/servers/{id}/action")
-public interface AdminActionsAsyncApi {
-
-   /**
-    * @see AdminActionsApi#suspendServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"suspend\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> suspendServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#resumeServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"resume\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> resumeServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#migrateServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"migrate\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> migrateServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#suspendServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"lock\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> lockServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#unlockServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"unlock\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> unlockServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#resetNetworkOfServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"resetNetwork\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> resetNetworkOfServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#createBackupOfServer
-    */
-   @POST
-   @Consumes(MediaType.APPLICATION_JSON)
-   @Produces(MediaType.APPLICATION_JSON)
-   @WrapWith("createBackup")
-   @ExceptionParser(MapHttp4xxCodesToExceptions.class)
-   @ResponseParser(ParseImageIdFromLocationHeader.class)
-   ListenableFuture<String> createBackupOfServer(@PathParam("id") String id,
-                                                  @PayloadParam("name") String imageName,
-                                                  @PayloadParam("backup_type") BackupType backupType,
-                                                  @PayloadParam("rotation") int rotation,
-                                                  CreateBackupOfServerOptions... options);
-
-   /**
-    * @see AdminActionsApi#pauseServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"pause\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> pauseServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#unpauseServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"unpause\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> unpauseServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#suspendServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @Payload("{\"injectNetworkInfo\":null}")
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> injectNetworkInfoIntoServer(@PathParam("id") String id);
-
-   /**
-    * @see AdminActionsApi#migrateServer(String)
-    */
-   @POST
-   @Produces(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   @WrapWith("os-migrateLive")
-   ListenableFuture<Boolean> liveMigrateServer(@PathParam("id") String id,
-                                               @PayloadParam("host") String host,
-                                               @PayloadParam("block_migration") boolean blockMigration,
-                                               @PayloadParam("disk_over_commit") boolean diskOverCommit);
-}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApi.java
index 5e8d19d..1274c69 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApi.java
@@ -22,10 +22,10 @@
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
-import org.jclouds.rest.annotations.RequestFilters;
+
+import com.google.common.annotations.Beta;
 
 /**
  * Provide access to extra metadata for Nova flavors.
@@ -35,9 +35,9 @@
  * @see org.jclouds.openstack.nova.v2_0.features.FlavorApi
  * @see org.jclouds.openstack.nova.v2_0.extensions.FlavorExtraSpecsAsyncApi
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.FLAVOR_EXTRA_SPECS)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
-@RequestFilters(AuthenticateRequest.class)
 public interface FlavorExtraSpecsApi {
 
    /**
@@ -45,7 +45,7 @@
     *
     * @return the set of extra metadata for the flavor
     */
-   Map<String, String> getAllExtraSpecs(String flavorId);
+   Map<String, String> getMetadata(String flavorId);
 
    /**
     * Creates or updates the extra specs for a given flavor
@@ -53,7 +53,7 @@
     * @param flavorId the id of the flavor to modify
     * @param specs    the extra specs to apply
     */
-   Boolean setAllExtraSpecs(String flavorId, Map<String, String> specs);
+   Boolean updateMetadata(String flavorId, Map<String, String> specs);
 
    /**
     * Return a single extra spec value
@@ -61,7 +61,7 @@
     * @param flavorId the id of the flavor to modify
     * @param key      the extra spec key to retrieve
     */
-   String getExtraSpec(String flavorId, String key);
+   String getMetadataKey(String flavorId, String key);
 
    /**
     * Creates or updates a single extra spec value
@@ -70,7 +70,7 @@
     * @param key      the extra spec key (when creating ensure this does not include whitespace or other difficult characters)
     * @param value    the value to associate with the key
     */
-   Boolean setExtraSpec(String flavorId, String key, String value);
+   Boolean updateMetadataEntry(String flavorId, String key, String value);
 
    /**
     * Deletes an extra spec
@@ -78,6 +78,6 @@
     * @param flavorId the id of the flavor to modify
     * @param key      the extra spec key to delete
     */
-   Boolean deleteExtraSpec(String flavorId, String key);
+   Boolean deleteMetadataKey(String flavorId, String key);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsAsyncApi.java
index e58ac22..d93342b 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsAsyncApi.java
@@ -19,7 +19,6 @@
 package org.jclouds.openstack.nova.v2_0.extensions;
 
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -31,7 +30,6 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
-import org.jclouds.concurrent.Timeout;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
@@ -47,6 +45,7 @@
 import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -57,59 +56,59 @@
  * @see org.jclouds.openstack.nova.v2_0.features.FlavorApi
  * @see FlavorExtraSpecsApi
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.FLAVOR_EXTRA_SPECS)
-@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 @RequestFilters(AuthenticateRequest.class)
 @Consumes(MediaType.APPLICATION_JSON)
 public interface FlavorExtraSpecsAsyncApi {
 
    /**
-    * @see FlavorExtraSpecsApi#getAllExtraSpecs(String)
+    * @see FlavorExtraSpecsApi#getMetadata(String)
     */
    @GET
    @SelectJson("extra_specs")
    @Path("/flavors/{flavor_id}/os-extra_specs")
    @ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
-   ListenableFuture<Map<String, String>> getAllExtraSpecs(@PathParam("flavor_id") String flavorId);
+   ListenableFuture<Map<String, String>> getMetadata(@PathParam("flavor_id") String flavorId);
 
    /**
-    * @see FlavorExtraSpecsApi#setExtraSpec(String, String, String)
+    * @see FlavorExtraSpecsApi#updateMetadataEntry(String, String, String)
     */
    @POST
    @Path("/flavors/{flavor_id}/os-extra_specs")
    @Produces(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
    @MapBinder(BindToJsonPayload.class)
-   ListenableFuture<Boolean> setAllExtraSpecs(@PathParam("flavor_id") String flavorId, @PayloadParam("extra_specs") Map<String, String> specs);
+   ListenableFuture<Boolean> updateMetadata(@PathParam("flavor_id") String flavorId, @PayloadParam("extra_specs") Map<String, String> specs);
 
    /**
-    * @see FlavorExtraSpecsApi#getExtraSpec(String, String)
+    * @see FlavorExtraSpecsApi#getMetadataKey(String, String)
     */
    @GET
    @Path("/flavors/{flavor_id}/os-extra_specs/{key}")
    @Unwrap
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<String> getExtraSpec(@PathParam("flavor_id") String flavorId, @PathParam("key") String key);
+   ListenableFuture<String> getMetadataKey(@PathParam("flavor_id") String flavorId, @PathParam("key") String key);
 
    /**
-    * @see FlavorExtraSpecsApi#setExtraSpec(String, String, String)
+    * @see FlavorExtraSpecsApi#updateMetadataEntry(String, String, String)
     */
    @PUT
    @Path("/flavors/{flavor_id}/os-extra_specs/{key}")
    @Produces(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
    @Payload("%7B\"{key}\":\"{value}\"%7D")
-   ListenableFuture<Boolean> setExtraSpec(@PathParam("flavor_id") String flavorId,
+   ListenableFuture<Boolean> updateMetadataEntry(@PathParam("flavor_id") String flavorId,
                                           @PathParam("key") @PayloadParam("key") String key,
                                           @PayloadParam("value") String value);
 
    /**
-    * @see FlavorExtraSpecsApi#deleteExtraSpec(String, String)
+    * @see FlavorExtraSpecsApi#deleteMetadataKey(String, String)
     */
    @DELETE
    @Path("/flavors/{flavor_id}/os-extra_specs/{key}")
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> deleteExtraSpec(@PathParam("flavor_id") String flavorId,
+   ListenableFuture<Boolean> deleteMetadataKey(@PathParam("flavor_id") String flavorId,
                                              @PathParam("key") String key);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApi.java
index 45ee544..33987cf 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -26,6 +25,9 @@
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides synchronous access to Floating IPs.
  * <p/>
@@ -33,6 +35,7 @@
  * @see FloatingIPAsyncApi
  * @author Jeremy Daggett
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.FLOATING_IPS)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface FloatingIPApi {
@@ -42,29 +45,29 @@
     * 
     * @return all Floating IPs
     */
-   Set<? extends FloatingIP> listFloatingIPs();
+   FluentIterable<? extends FloatingIP> list();
 
    /**
     * Get a specific Floating IP address
     * 
     * @return all Floating IPs
     */
-   FloatingIP getFloatingIP(String id);
+   FloatingIP get(String id);
 
    /**
     * Allocate a Floating IP address
     * 
-    * @return a newly allocated FloatingIP
+    * @return a newly created FloatingIP
     */
-   FloatingIP allocate();
+   FloatingIP create();
 
    /**
-    * Deallocate a Floating IP address
+    * Decreate a Floating IP address
     * 
     * @param id
     *           the Floating IP id
     */
-   void deallocate(String id);
+   void delete(String id);
 
    /**
     * Add a Floating IP address to a Server
@@ -76,7 +79,7 @@
     * 
     *           NOTE: Possibly move this to ServerApi?
     */
-   void addFloatingIPToServer(String address, String serverId);
+   void addToServer(String address, String serverId);
 
    /**
     * Remove a Floating IP address from a Server
@@ -88,5 +91,5 @@
     * 
     *           NOTE: Possibly move this to ServerApi?
     */
-   void removeFloatingIPFromServer(String address, String serverId);
+   void removeFromServer(String address, String serverId);
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPAsyncApi.java
index d0db242..391de9f 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -40,9 +38,11 @@
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -57,33 +57,34 @@
  * @see <a href="http://nova.openstack.org/api_ext" />
  * @see <a href="http://wiki.openstack.org/os_api_floating_ip"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.FLOATING_IPS)
 @SkipEncoding( { '/', '=' })
 @RequestFilters(AuthenticateRequest.class)
 public interface FloatingIPAsyncApi {
 
    /**
-    * @see FloatingIPApi#listFloatingIPs
+    * @see FloatingIPApi#list
     */
    @GET
    @Path("/os-floating-ips")
    @SelectJson("floating_ips")
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends FloatingIP>> listFloatingIPs();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends FloatingIP>> list();
 
    /**
-    * @see FloatingIPApi#getFloatingIP
+    * @see FloatingIPApi#get
     */
    @GET
    @Path("/os-floating-ips/{id}")
    @SelectJson("floating_ip")
    @Consumes(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends FloatingIP> getFloatingIP(@PathParam("id") String id);
+   ListenableFuture<? extends FloatingIP> get(@PathParam("id") String id);
 
    /**
-    * @see FloatingIPApi#allocate
+    * @see FloatingIPApi#create
     */
    @POST
    @Path("/os-floating-ips")
@@ -92,37 +93,37 @@
    @Produces(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
    @Payload("{}")
-   ListenableFuture<? extends FloatingIP> allocate();
+   ListenableFuture<? extends FloatingIP> create();
 
    /**
-    * @see FloatingIPApi#deallocate
+    * @see FloatingIPApi#delete
     */
    @DELETE
    @Consumes(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
    @Path("/os-floating-ips/{id}")
-   ListenableFuture<Void> deallocate(@PathParam("id") String id);
+   ListenableFuture<Void> delete(@PathParam("id") String id);
 
    /**
-    * @see FloatingIPApi#addFloatingIPToServer
+    * @see FloatingIPApi#addToServer
     */
    @POST
    @Path("/servers/{server}/action")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"addFloatingIp\":%7B\"address\":\"{address}\"%7D%7D")
-   ListenableFuture<Void> addFloatingIPToServer(@PayloadParam("address") String address,
+   ListenableFuture<Void> addToServer(@PayloadParam("address") String address,
             @PathParam("server") String serverId);
 
    /**
-    * @see FloatingIPApi#removeFloatingIPFromServer
+    * @see FloatingIPApi#removeFromServer
     */
    @POST
    @Path("/servers/{server}/action")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"removeFloatingIp\":%7B\"address\":\"{address}\"%7D%7D")
-   ListenableFuture<Void> removeFloatingIPFromServer(@PayloadParam("address") String address,
+   ListenableFuture<Void> removeFromServer(@PayloadParam("address") String address,
             @PathParam("server") String serverId);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApi.java
index 5b1666f..1a9c594 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -27,6 +26,9 @@
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides asynchronous access to Host Administration features via the REST API.
  * <p/>
@@ -34,6 +36,7 @@
  * @author Adam Lowe
  * @see HostAdministrationAsyncApi
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.HOSTS)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface HostAdministrationApi {
@@ -43,28 +46,28 @@
     *
     * @return the usage information
     */
-   Set<? extends Host> listHosts();
+   FluentIterable<? extends Host> list();
 
    /**
     * Retrieves the physical/usage resource on a specific host
     *
     * @return the usage information
     */
-   Set<? extends HostResourceUsage> getHostResourceUsage(String hostId);
+   FluentIterable<? extends HostResourceUsage> listResourceUsage(String hostId);
 
    /**
     * Allow the specified host to accept new instances.
     *
     * @return true if successful
     */
-   Boolean enableHost(String hostId);
+   boolean enable(String hostId);
 
    /**
     * Prevent the specified host from accepting new instances.
     *
     * @return true if successful
     */
-   Boolean disableHost(String hostId);
+   boolean disable(String hostId);
 
    /**
     * Start host maintenance window.
@@ -73,34 +76,34 @@
     *
     * @return true if successful
     */
-   Boolean startHostMaintenance(String hostId);
+   boolean startMaintenance(String hostId);
 
    /**
     * Stop host maintenance window.
     *
     * @return true if successful
     */
-   Boolean stopHostMaintenance(String hostId);
+   boolean stopMaintenance(String hostId);
 
    /**
     * Startup a host.
     *
     * @return true if successful
     */
-   Boolean startupHost(String hostId);
+   boolean startup(String hostId);
 
    /**
     * Shutdown a host.
     *
     * @return true if successful
     */
-   Boolean shutdownHost(String hostId);
+   boolean shutdown(String hostId);
 
    /**
     * Reboot a host.
     *
     * @return true if successful
     */
-   Boolean rebootHost(String hostId);
+   boolean reboot(String hostId);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationAsyncApi.java
index 89ea47f..dcf9f9f 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.PUT;
@@ -46,8 +44,10 @@
 import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -60,6 +60,7 @@
  * @see <a href="http://nova.openstack.org/api_ext" />
  * @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.hosts.html" />
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.HOSTS)
 @SkipEncoding({'/', '='})
 @RequestFilters(AuthenticateRequest.class)
@@ -68,83 +69,83 @@
 public interface HostAdministrationAsyncApi {
 
    /**
-    * @see HostAdministrationApi#listHosts()
+    * @see HostAdministrationApi#list()
     */
    @GET
    @SelectJson("hosts")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Host>> listHosts();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends Host>> list();
 
    /**
-    * @see HostAdministrationApi#getHostResourceUsage(String)
+    * @see HostAdministrationApi#listResourceUsage(String)
     */
    @GET
    @Path("/{id}")
    @SelectJson("host")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends HostResourceUsage>> getHostResourceUsage(@PathParam("id") String hostId);
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends HostResourceUsage>> listResourceUsage(@PathParam("id") String hostId);
 
    /**
-    * @see HostAdministrationApi#enableHost(String)
+    * @see HostAdministrationApi#enable(String)
     */
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{id}")
    @Payload("{\"status\":\"enable\"}")
    @ResponseParser(StatusEnabledResponseParser.class)
-   ListenableFuture<Boolean> enableHost(@PathParam("id") String hostId);
+   ListenableFuture<Boolean> enable(@PathParam("id") String hostId);
 
    /**
-    * @see HostAdministrationApi#disableHost(String) 
+    * @see HostAdministrationApi#disable(String) 
     */
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{id}")
    @Payload("{\"status\":\"disable\"}")
    @ResponseParser(StatusDisabledResponseParser.class)
-   ListenableFuture<Boolean> disableHost(@PathParam("id") String hostId);
+   ListenableFuture<Boolean> disable(@PathParam("id") String hostId);
 
    /**
-    * @see HostAdministrationApi#startHostMaintenance(String)
+    * @see HostAdministrationApi#startMaintenance(String)
     */
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{id}")
    @Payload("{\"maintenance_mode\":\"enable\"}")
    @ResponseParser(MaintenanceModeEnabledResponseParser.class)
-   ListenableFuture<Boolean> startHostMaintenance(@PathParam("id") String hostId);
+   ListenableFuture<Boolean> startMaintenance(@PathParam("id") String hostId);
 
    /**
-    * @see HostAdministrationApi#stopHostMaintenance(String)
+    * @see HostAdministrationApi#stopMaintenance(String)
     */
    @PUT
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{id}")
    @Payload("{\"maintenance_mode\":\"disable\"}")
    @ResponseParser(MaintenanceModeDisabledResponseParser.class)
-   ListenableFuture<Boolean> stopHostMaintenance(@PathParam("id") String hostId);
+   ListenableFuture<Boolean> stopMaintenance(@PathParam("id") String hostId);
 
    /**
-    * @see HostAdministrationApi#startupHost(String)
+    * @see HostAdministrationApi#startup(String)
     */
    @GET
    @Path("/{id}/startup")
    @ResponseParser(PowerIsStartupResponseParser.class)
-   ListenableFuture<Boolean> startupHost(@PathParam("id") String hostId);
+   ListenableFuture<Boolean> startup(@PathParam("id") String hostId);
 
    /**
-    * @see HostAdministrationApi#shutdownHost(String)
+    * @see HostAdministrationApi#shutdown(String)
     */
    @GET
    @Path("/{id}/shutdown")
    @ResponseParser(PowerIsShutdownResponseParser.class)
-   ListenableFuture<Boolean> shutdownHost(@PathParam("id") String hostId);
+   ListenableFuture<Boolean> shutdown(@PathParam("id") String hostId);
 
    /**
-    * @see HostAdministrationApi#rebootHost(String)
+    * @see HostAdministrationApi#reboot(String)
     */
    @GET
    @Path("/{id}/reboot")
    @ResponseParser(PowerIsRebootResponseParser.class)
-   ListenableFuture<Boolean> rebootHost(@PathParam("id") String hostId);
+   ListenableFuture<Boolean> reboot(@PathParam("id") String hostId);
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApi.java
index 61bc112..0d8ecd0 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApi.java
@@ -19,15 +19,15 @@
 package org.jclouds.openstack.nova.v2_0.extensions;
 
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.nova.v2_0.domain.HostAggregate;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
-import org.jclouds.rest.annotations.RequestFilters;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 
 /**
  * Provide access to Host Aggregates in Nova (alias "OS-AGGREGATES")
@@ -37,29 +37,29 @@
  * @see <a href="http://nova.openstack.org/api_ext/ext_aggregates.html"/>
  * @see <a href="http://wiki.openstack.org/host-aggregates"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.AGGREGATES)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
-@RequestFilters(AuthenticateRequest.class)
 public interface HostAggregateApi {
 
    /**
     * @return the set of host aggregates.
     */
-   Set<? extends HostAggregate> listAggregates();
+   FluentIterable<? extends HostAggregate> list();
 
    /**
     * Retrieves the details of an aggregate, hosts and metadata included.
     *
     * @return the details of the aggregate requested.
     */
-   HostAggregate getAggregate(String id);
+   HostAggregate get(String id);
 
    /**
     * Creates an aggregate, given its name and availability zone.
     * 
     * @return the newly created Aggregate
     */
-   HostAggregate createAggregate(String name, String availabilityZone);
+   HostAggregate createInAvailabilityZone(String name, String availabilityZone);
 
    /**
     * Updates the name of an aggregate.
@@ -74,7 +74,7 @@
    /**
     * Removes an aggregate.
     */
-   Boolean deleteAggregate(String id);
+   Boolean delete(String id);
 
    /**
     * Adds a host to an aggregate
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateAsyncApi.java
index a964b48..54bd93f 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateAsyncApi.java
@@ -19,8 +19,6 @@
 package org.jclouds.openstack.nova.v2_0.extensions;
 
 import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -31,7 +29,6 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
-import org.jclouds.concurrent.Timeout;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.nova.v2_0.domain.HostAggregate;
 import org.jclouds.openstack.v2_0.ServiceType;
@@ -41,10 +38,12 @@
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.WrapWith;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -53,40 +52,40 @@
  * @author Adam Lowe
  * @see HostAggregateApi
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.AGGREGATES)
-@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 @RequestFilters(AuthenticateRequest.class)
 @Path("/os-aggregates")
 public interface HostAggregateAsyncApi {
 
    /**
-    * @see HostAggregateApi#listAggregates()
+    * @see HostAggregateApi#list()
     */
    @GET
    @SelectJson("aggregates")
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends HostAggregate>> listAggregates();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends HostAggregate>> list();
 
    /**
-    * @see HostAggregateApi#getAggregate(String)
+    * @see HostAggregateApi#get(String)
     */
    @GET
    @Path("/{id}")
    @SelectJson("aggregate")
    @Consumes(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends HostAggregate> getAggregate(@PathParam("id") String id);
+   ListenableFuture<? extends HostAggregate> get(@PathParam("id") String id);
 
    /**
-    * @see HostAggregateApi#createAggregate(String, String)
+    * @see HostAggregateApi#createInAvailabilityZone(String, String)
     */
    @POST
    @SelectJson("aggregate")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @WrapWith("aggregate")
-   ListenableFuture<? extends HostAggregate> createAggregate(@PayloadParam("name") String name,
+   ListenableFuture<? extends HostAggregate> createInAvailabilityZone(@PayloadParam("name") String name,
                                                    @PayloadParam("availability_zone") String availabilityZone);
 
    /**
@@ -110,13 +109,13 @@
    ListenableFuture<? extends HostAggregate> updateAvailabilityZone(@PathParam("id") String id, @PayloadParam("availability_zone") String availabilityZone);
    
    /**
-    * @see HostAggregateApi#deleteAggregate(String)
+    * @see HostAggregateApi#delete(String)
     */
    @DELETE
    @Path("/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> deleteAggregate(@PathParam("id") String id);
+   ListenableFuture<Boolean> delete(@PathParam("id") String id);
 
    /**
     * @see HostAggregateApi#addHost(String,String)
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApi.java
index 1d5ae3c..a276939 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -27,6 +25,9 @@
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides synchronous access to Security Groups.
  * <p/>
@@ -34,6 +35,7 @@
  * @see KeyPairAsyncApi
  * @author Jeremy Daggett
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.KEYPAIRS)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface KeyPairApi {
@@ -43,27 +45,27 @@
     * 
     * @return all Key Pairs
     */
-   Set<? extends Map<String, ? extends KeyPair>> listKeyPairs();
+   FluentIterable<? extends KeyPair> list();
 
    /**
     * Create a Key Pair.
     * 
     * @return a Key Pair
     */
-   KeyPair createKeyPair(String name);
+   KeyPair create(String name);
 
    /**
     * Create a Key Pair with a public key.
     * 
     * @return a Key Pair with a public key.
     */
-   KeyPair createKeyPairWithPublicKey(String name, String publicKey);
+   KeyPair createWithPublicKey(String name, String publicKey);
 
    /**
     * Delete a Key Pairs.
     * 
     * @return
     */
-   Boolean deleteKeyPair(String name);
+   boolean delete(String name);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairAsyncApi.java
index 3fb1056..c5b0f69 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairAsyncApi.java
@@ -18,9 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Map;
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -32,6 +29,7 @@
 
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseKeyPairs;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
 import org.jclouds.openstack.v2_0.services.Extension;
@@ -39,11 +37,14 @@
 import org.jclouds.rest.annotations.Payload;
 import org.jclouds.rest.annotations.PayloadParam;
 import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -59,6 +60,7 @@
  * @see <a href="http://nova.openstack.org/api_ext" />
  * @see <a href="http://nova.openstack.org/api_ext/ext_keypairs.html" />
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.KEYPAIRS)
 @SkipEncoding({ '/', '=' })
 @RequestFilters(AuthenticateRequest.class)
@@ -66,10 +68,10 @@
 
    @GET
    @Path("/os-keypairs")
-   @SelectJson("keypairs")
+   @ResponseParser(ParseKeyPairs.class)
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Map<String, ? extends KeyPair>>> listKeyPairs();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends KeyPair>> list();
 
    @POST
    @Path("/os-keypairs")
@@ -77,7 +79,7 @@
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"keypair\":%7B\"name\":\"{name}\"%7D%7D")
-   ListenableFuture<? extends KeyPair> createKeyPair(@PayloadParam("name") String name);
+   ListenableFuture<? extends KeyPair> create(@PayloadParam("name") String name);
 
    @POST
    @Path("/os-keypairs")
@@ -85,13 +87,13 @@
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"keypair\":%7B\"name\":\"{name}\",\"public_key\":\"{publicKey}\"%7D%7D")
-   ListenableFuture<? extends KeyPair> createKeyPairWithPublicKey(@PayloadParam("name") String name,
+   ListenableFuture<? extends KeyPair> createWithPublicKey(@PayloadParam("name") String name,
          @PayloadParam("publicKey") String publicKey);
 
    @DELETE
    @Path("/os-keypairs/{name}")
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
    @Consumes
-   ListenableFuture<Boolean> deleteKeyPair(@PathParam("name") String name);
+   ListenableFuture<Boolean> delete(@PathParam("name") String name);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApi.java
index 9a38d1f..af313b9 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApi.java
@@ -21,11 +21,11 @@
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
-import org.jclouds.openstack.nova.v2_0.domain.Quotas;
+import org.jclouds.openstack.nova.v2_0.domain.Quota;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
-import org.jclouds.rest.annotations.RequestFilters;
+
+import com.google.common.annotations.Beta;
 
 /**
  * The quotas extension enables limiters placed on the resources used per tenant (project) for virtual instances. It is
@@ -38,26 +38,26 @@
  * @see QuotaAsyncApi
  * @see <a href="http://nova.openstack.org/api_ext/ext_quotas.html"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.QUOTAS)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
-@RequestFilters(AuthenticateRequest.class)
 public interface QuotaApi {
 
    /**
     * @return the quota settings for the tenant
     */
-   Quotas getQuotasForTenant(String tenantId);
+   Quota getByTenant(String tenantId);
 
    /**
     * Update the quotas for a given tenant
     *
     * @return true if successful
     */
-   Boolean updateQuotasForTenant(String tenantId, Quotas quotas);
+   boolean updateQuotaOfTenant(Quota quota, String tenantId);
 
    /**
     * @return the set of default quotas for the tenant
     */
-   Quotas getDefaultQuotasForTenant(String tenantId);
+   Quota getDefaultsForTenant(String tenantId);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaAsyncApi.java
index b0f6dc7..1626986 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.concurrent.TimeUnit;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.PUT;
@@ -28,9 +26,8 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
-import org.jclouds.concurrent.Timeout;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
-import org.jclouds.openstack.nova.v2_0.domain.Quotas;
+import org.jclouds.openstack.nova.v2_0.domain.Quota;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 import org.jclouds.rest.annotations.ExceptionParser;
@@ -41,48 +38,50 @@
 import org.jclouds.rest.binders.BindToJsonPayload;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * Provide access to Quota information for Nova tenants.
- *
+ * 
  * @author Adam Lowe
  * @see QuotaApi
  * @see <a href="http://nova.openstack.org/api_ext/ext_quotas.html"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.QUOTAS)
-@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 @RequestFilters(AuthenticateRequest.class)
 @Path("/os-quota-sets")
 public interface QuotaAsyncApi {
 
    /**
-    * @see QuotaApi#getDefaultQuotasForTenant(String)
+    * @see QuotaApi#getDefaultsForTenant(String)
     */
    @GET
    @SelectJson("quota_set")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/{tenant_id}")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends Quotas> getQuotasForTenant(@PathParam("tenant_id") String tenantId);
+   ListenableFuture<? extends Quota> getByTenant(@PathParam("tenant_id") String tenantId);
 
    /**
-    * @see QuotaApi#updateQuotasForTenant(String, org.jclouds.openstack.nova.v2_0.domain.Quotas)
+    * @see QuotaApi#updateQuotaOfTenant
     */
    @PUT
    @Path("/{tenant_id}")
    @Produces(MediaType.APPLICATION_JSON)
    @MapBinder(BindToJsonPayload.class)
-   ListenableFuture<Boolean> updateQuotasForTenant(@PathParam("tenant_id") String tenantId, @PayloadParam("quota_set") Quotas quotas);
+   ListenableFuture<Boolean> updateQuotaOfTenant(@PayloadParam("quota_set") Quota quota,
+            @PathParam("tenant_id") String tenantId);
 
    /**
-    * @see QuotaApi#getDefaultQuotasForTenant(String)
+    * @see QuotaApi#getDefaultsForTenant(String)
     */
    @GET
    @SelectJson("quota_set")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/{tenant_id}/defaults")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends Quotas> getDefaultQuotasForTenant(@PathParam("tenant_id") String tenantId);
+   ListenableFuture<? extends Quota> getDefaultsForTenant(@PathParam("tenant_id") String tenantId);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApi.java
index 86922ce..aed2b37 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApi.java
@@ -21,11 +21,11 @@
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.nova.v2_0.domain.QuotaClass;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
-import org.jclouds.rest.annotations.RequestFilters;
+
+import com.google.common.annotations.Beta;
 
 /**
  * Provides synchronous access to Quota Classes via the REST API.
@@ -37,21 +37,21 @@
  * @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.quota_classes.html"/>
  * @see <a href="http://wiki.openstack.org/QuotaClass"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.QUOTA_CLASSES)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
-@RequestFilters(AuthenticateRequest.class)
 public interface QuotaClassApi {
 
    /**
     * @return the quota settings for the tenant
     */
-   QuotaClass getQuotaClass(String id);
+   QuotaClass get(String id);
 
    /**
     * Update the quotas for a given tenant
     *
     * @return true if successful
     */
-   Boolean updateQuotaClass(String id, QuotaClass quotas);
+   boolean update(String id, QuotaClass quotas);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassAsyncApi.java
index 41cfe91..b614bea 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.concurrent.TimeUnit;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.PUT;
@@ -28,7 +26,6 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
-import org.jclouds.concurrent.Timeout;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.nova.v2_0.domain.QuotaClass;
 import org.jclouds.openstack.v2_0.ServiceType;
@@ -41,6 +38,7 @@
 import org.jclouds.rest.binders.BindToJsonPayload;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -51,29 +49,29 @@
  * @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.quota_classes.html"/>
  * @see <a href="http://wiki.openstack.org/QuotaClass"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.QUOTA_CLASSES)
-@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 @RequestFilters(AuthenticateRequest.class)
 @Path("/os-quota-class-sets")
 public interface QuotaClassAsyncApi {
 
    /**
-    * @see QuotaClassApi#getQuotaClass
+    * @see QuotaClassApi#get
     */
    @GET
    @SelectJson("quota_class_set")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/{id}")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends QuotaClass> getQuotaClass(@PathParam("id") String id);
+   ListenableFuture<? extends QuotaClass> get(@PathParam("id") String id);
 
    /**
-    * @see QuotaClassApi#updateQuotaClass
+    * @see QuotaClassApi#update
     */
    @PUT
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    @MapBinder(BindToJsonPayload.class)
-   ListenableFuture<Boolean> updateQuotaClass(@PathParam("id") String id, @PayloadParam("quota_class_set") QuotaClass quotas);
+   ListenableFuture<Boolean> update(@PathParam("id") String id, @PayloadParam("quota_class_set") QuotaClass quotas);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApi.java
index 8042ad2..f381131 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -28,6 +27,9 @@
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides synchronous access to Security Groups.
  * <p/>
@@ -35,6 +37,7 @@
  * @see SecurityGroupAsyncApi
  * @author Jeremy Daggett
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.SECURITY_GROUPS)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface SecurityGroupApi {
@@ -42,44 +45,44 @@
    /**
     * List all Security Groups.
     * 
-    * @return all Floating IPs
+    * @return all Security Groups
     */
-   Set<? extends SecurityGroup> listSecurityGroups();
+   FluentIterable<? extends SecurityGroup> list();
 
    /**
     * Get a specific Security Group
     * 
     * @return a specific Security Group
     */
-   SecurityGroup getSecurityGroup(String id);
+   SecurityGroup get(String id);
 
    /**
     * Create a Security Group
     * 
     * @return a new Security Group
     */
-   SecurityGroup createSecurityGroupWithNameAndDescription(String name, String description);
+   SecurityGroup createWithDescription(String name, String description);
 
    /**
     * Delete a Security Group.
     * 
     * @return
     */
-   Boolean deleteSecurityGroup(String id);
+   boolean delete(String id);
 
    /**
     * Create a Security Group Rule.
     * 
     * @return a new Security Group Rule
     */
-   SecurityGroupRule createSecurityGroupRuleAllowingCidrBlock(String parentGroup, Ingress ingress, String sourceCidr);
+   SecurityGroupRule createRuleAllowingCidrBlock(String parentGroup, Ingress ingress, String sourceCidr);
 
    /**
     * Create a Security Group Rule.
     * 
     * @return a new Security Group Rule
     */
-   SecurityGroupRule createSecurityGroupRuleAllowingSecurityGroupId(String parentGroup, Ingress ingress,
+   SecurityGroupRule createRuleAllowingSecurityGroupId(String parentGroup, Ingress ingress,
             String sourceCidr);
 
    /**
@@ -87,6 +90,6 @@
     * 
     * @return
     */
-   Boolean deleteSecurityGroupRule(String id);
+   Boolean deleteRule(String id);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupAsyncApi.java
index 438c85e..0303ff8 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -43,10 +41,12 @@
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -60,33 +60,34 @@
  * @see <a href="http://nova.openstack.org/api_ext" />
  * @see <a href="http://wiki.openstack.org/os-security-groups" />
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.SECURITY_GROUPS)
 @SkipEncoding( { '/', '=' })
 @RequestFilters(AuthenticateRequest.class)
 public interface SecurityGroupAsyncApi {
 
    /**
-    * @see SecurityGroupApi#listSecurityGroups
+    * @see SecurityGroupApi#list
     */
    @GET
    @SelectJson("security_groups")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/os-security-groups")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends SecurityGroup>> listSecurityGroups();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends SecurityGroup>> list();
 
    /**
-    * @see SecurityGroupApi#getSecurityGroup
+    * @see SecurityGroupApi#get
     */
    @GET
    @Path("/os-security-groups/{id}")
    @SelectJson("security_group")
    @Consumes(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends SecurityGroup> getSecurityGroup(@PathParam("id") String id);
+   ListenableFuture<? extends SecurityGroup> get(@PathParam("id") String id);
 
    /**
-    * @see SecurityGroupApi#createSecurityGroupWithNameAndDescription
+    * @see SecurityGroupApi#createWithDescription
     */
    @POST
    @Path("/os-security-groups")
@@ -95,20 +96,20 @@
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"security_group\":%7B\"name\":\"{name}\",\"description\":\"{description}\"%7D%7D")
-   ListenableFuture<? extends SecurityGroup> createSecurityGroupWithNameAndDescription(@PayloadParam("name") String name,
+   ListenableFuture<? extends SecurityGroup> createWithDescription(@PayloadParam("name") String name,
             @PayloadParam("description") String description);
 
    /**
-    * @see SecurityGroupApi#deleteSecurityGroup
+    * @see SecurityGroupApi#delete
     */
    @DELETE
    @Path("/os-security-groups/{id}")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
    @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Boolean> deleteSecurityGroup(@PathParam("id") String id);
+   ListenableFuture<Boolean> delete(@PathParam("id") String id);
 
    /**
-    * @see SecurityGroupApi#createSecurityGroupRuleAllowingCidrBlock
+    * @see SecurityGroupApi#createRuleAllowingCidrBlock
     */
    @POST
    @Path("/os-security-group-rules")
@@ -117,7 +118,7 @@
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @MapBinder(BindSecurityGroupRuleToJsonPayload.class)
-   ListenableFuture<? extends SecurityGroupRule> createSecurityGroupRuleAllowingCidrBlock(
+   ListenableFuture<? extends SecurityGroupRule> createRuleAllowingCidrBlock(
             @PayloadParam("parent_group_id") String parent_group_id, Ingress ip_protocol,
             @PayloadParam("cidr") String cidr);
 
@@ -131,17 +132,17 @@
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @MapBinder(BindSecurityGroupRuleToJsonPayload.class)
-   ListenableFuture<? extends SecurityGroupRule> createSecurityGroupRuleAllowingSecurityGroupId(
+   ListenableFuture<? extends SecurityGroupRule> createRuleAllowingSecurityGroupId(
             @PayloadParam("parent_group_id") String parent_group_id, Ingress ip_protocol,
             @PayloadParam("group_id") String group_id);
 
    /**
-    * @see SecurityGroupApi#deleteSecurityGroupRule
+    * @see SecurityGroupApi#deleteRule
     */
    @DELETE
    @Path("/os-security-group-rules/{security_group_rule_ID}")
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
    @Consumes
-   ListenableFuture<Boolean> deleteSecurityGroupRule(@PathParam("security_group_rule_ID") String security_group_rule_ID);
+   ListenableFuture<Boolean> deleteRule(@PathParam("security_group_rule_ID") String security_group_rule_ID);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerAdminApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerAdminApi.java
new file mode 100644
index 0000000..351bb78
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerAdminApi.java
@@ -0,0 +1,126 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.extensions;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.openstack.nova.v2_0.domain.BackupType;
+import org.jclouds.openstack.nova.v2_0.options.CreateBackupOfServerOptions;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.openstack.v2_0.services.Extension;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Provide additional actions for servers:
+ * 'suspend', 'resume', 'migrate', 'lock', 'unlock', 'resetNetwork', 'createBackup', 'pause', 'migrateLive',
+ * 'injectNetworkInfo', 'unpause'
+ *
+ * @author Adam Lowe
+ * @see org.jclouds.openstack.nova.v2_0.extensions.ServerAdminAsyncApi
+ */
+@Beta
+@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS)
+@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
+public interface ServerAdminApi {
+
+   /**
+    * Suspend a server.
+    *
+    * @param id id of the server
+    */
+   Boolean suspend(String id);
+
+   /**
+    * Resume a server.
+    *
+    * @param id id of the server
+    */
+   Boolean resume(String id);
+
+   /**
+    * Migrate a server.
+    *
+    * @param id id of the server
+    */
+   Boolean migrate(String id);
+
+   /**
+    * Lock a server.
+    *
+    * @param id id of the server
+    */
+   Boolean lock(String id);
+
+   /**
+    * Unlock a server.
+    *
+    * @param id id of the server
+    */
+   Boolean unlock(String id);
+
+   /**
+    * Reset network of a server.
+    *
+    * @param id id of the server
+    */
+   Boolean resetNetwork(String id);
+
+   /**
+    * Create backup of a server.
+    *
+    * @param id         id of the server
+    * @param imageName  the name of the image to create
+    * @param backupType the type of backup
+    * @param rotation   the number of images to retain (0 to simply overwrite)
+    * @param options    optional rotation and/or metadata parameters
+    * @return the id of the newly created image
+    */
+   String createBackup(String id, String imageName, BackupType backupType, int rotation, CreateBackupOfServerOptions... options);
+
+   /**
+    * Pause a server.
+    *
+    * @param id id of the server
+    */
+   Boolean pause(String id);
+
+   /**
+    * Unpause a server.
+    *
+    * @param id id of the server
+    */
+   Boolean unpause(String id);
+
+
+   /**
+    * Live migrate a server.
+    *
+    * @param id id of the server
+    */
+   Boolean liveMigrate(String id, String host, boolean blockMigration, boolean diskOverCommit);
+
+   /**
+    * Inject network info into a server.
+    *
+    * @param id id of the server
+    */
+   Boolean injectNetworkInfo(String id);
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerAdminAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerAdminAsyncApi.java
new file mode 100644
index 0000000..f6ce679
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerAdminAsyncApi.java
@@ -0,0 +1,167 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.extensions;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.nova.v2_0.domain.BackupType;
+import org.jclouds.openstack.nova.v2_0.functions.ParseImageIdFromLocationHeader;
+import org.jclouds.openstack.nova.v2_0.options.CreateBackupOfServerOptions;
+import org.jclouds.openstack.v2_0.ServiceType;
+import org.jclouds.openstack.v2_0.services.Extension;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.annotations.WrapWith;
+import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
+import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
+
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provide access to Admin Server Actions via REST API
+ *
+ * @author Adam Lowe
+ * @see org.jclouds.openstack.nova.v2_0.extensions.ServerAdminApi
+ */
+@Beta
+@Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.ADMIN_ACTIONS)
+@SkipEncoding( { '/', '=' })
+@RequestFilters(AuthenticateRequest.class)
+@Path("/servers/{id}/action")
+public interface ServerAdminAsyncApi {
+
+   /**
+    * @see ServerAdminApi#suspend(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"suspend\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> suspend(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#resume(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"resume\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> resume(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#migrate(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"migrate\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> migrate(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#lock(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"lock\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> lock(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#unlock(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"unlock\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> unlock(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#resetNetwork(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"resetNetwork\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> resetNetwork(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#createBackup
+    */
+   @POST
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Produces(MediaType.APPLICATION_JSON)
+   @WrapWith("createBackup")
+   @ExceptionParser(MapHttp4xxCodesToExceptions.class)
+   @ResponseParser(ParseImageIdFromLocationHeader.class)
+   ListenableFuture<String> createBackup(@PathParam("id") String id,
+                                                  @PayloadParam("name") String imageName,
+                                                  @PayloadParam("backup_type") BackupType backupType,
+                                                  @PayloadParam("rotation") int rotation,
+                                                  CreateBackupOfServerOptions... options);
+
+   /**
+    * @see ServerAdminApi#pause(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"pause\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> pause(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#unpause(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"unpause\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> unpause(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#injectNetworkInfo(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @Payload("{\"injectNetworkInfo\":null}")
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   ListenableFuture<Boolean> injectNetworkInfo(@PathParam("id") String id);
+
+   /**
+    * @see ServerAdminApi#liveMigrate(String)
+    */
+   @POST
+   @Produces(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
+   @WrapWith("os-migrateLive")
+   ListenableFuture<Boolean> liveMigrate(@PathParam("id") String id,
+                                               @PayloadParam("host") String host,
+                                               @PayloadParam("block_migration") boolean blockMigration,
+                                               @PayloadParam("disk_over_commit") boolean diskOverCommit);
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApi.java
index 6910cb2..c14138c 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApi.java
@@ -25,6 +25,8 @@
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 
+import com.google.common.annotations.Beta;
+
 /**
  * Provides synchronous access to Server details including security group, referred to as the CREATESERVEREXT extension
  * in the nova documentation
@@ -37,6 +39,7 @@
  * @see ServerWithSecurityGroupsAsyncApi
  * @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.createserverext.html"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.CREATESERVEREXT)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface ServerWithSecurityGroupsApi {
@@ -47,6 +50,6 @@
     * @param id id of the server
     * @return server or null if not found
     */
-   ServerWithSecurityGroups getServer(String id);
+   ServerWithSecurityGroups get(String id);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsAsyncApi.java
index 30b8375..9585b30 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsAsyncApi.java
@@ -34,6 +34,7 @@
 import org.jclouds.rest.annotations.SkipEncoding;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -44,19 +45,20 @@
  * @see ServerWithSecurityGroupsApi
  * @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.createserverext.html"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.CREATESERVEREXT)
 @SkipEncoding({'/', '='})
 @RequestFilters(AuthenticateRequest.class)
 public interface ServerWithSecurityGroupsAsyncApi {
 
    /**
-    * @see ServerWithSecurityGroupsApi#getServer(String)
+    * @see ServerWithSecurityGroupsApi#get(String)
     */
    @GET
    @SelectJson("server")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/os-create-server-ext/{id}")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends ServerWithSecurityGroups> getServer(@PathParam("id") String id);
+   ListenableFuture<? extends ServerWithSecurityGroups> get(@PathParam("id") String id);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApi.java
index d17eb19..a28c4ec 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -26,6 +25,9 @@
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides asynchronous access to Simple Tenant Usage via the REST API.
  * <p/>
@@ -33,6 +35,7 @@
  * @author Adam Lowe
  * @see SimpleTenantUsageAsyncApi
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.SIMPLE_TENANT_USAGE)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface SimpleTenantUsageApi {
@@ -42,12 +45,12 @@
     *
     * @return the set of TenantUsage reports
     */
-   Set<? extends SimpleTenantUsage> listTenantUsages();
+   FluentIterable<? extends SimpleTenantUsage> list();
 
    /**
     * Retrieve tenant_usage for a specified tenant
     *
     * @return the requested tenant usage
     */
-   SimpleTenantUsage getTenantUsage(String tenantId);
+   SimpleTenantUsage get(String tenantId);
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageAsyncApi.java
index 729f50e..ea14d37 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -34,9 +32,11 @@
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -49,29 +49,30 @@
  * @see <a href="http://nova.openstack.org/api_ext" />
  * @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.simple_tenant_usage.html" />
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.SIMPLE_TENANT_USAGE)
 @SkipEncoding({'/', '='})
 @RequestFilters(AuthenticateRequest.class)
 public interface SimpleTenantUsageAsyncApi {
 
    /**
-    * @see SimpleTenantUsageApi#listTenantUsages()
+    * @see SimpleTenantUsageApi#list()
     */
    @GET
    @Path("/os-simple-tenant-usage")
    @SelectJson("tenant_usages")
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends SimpleTenantUsage>> listTenantUsages();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends SimpleTenantUsage>> list();
 
    /**
-    * @see SimpleTenantUsageApi#getTenantUsage(String)
+    * @see SimpleTenantUsageApi#get(String)
     */
    @GET
    @Path("/os-simple-tenant-usage/{id}")
    @SelectJson("tenant_usage")
    @Consumes(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends SimpleTenantUsage> getTenantUsage(@PathParam("id") String tenantId);
+   ListenableFuture<? extends SimpleTenantUsage> get(@PathParam("id") String tenantId);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApi.java
index 257dea3..b3c1027 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -26,12 +25,16 @@
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides synchronous access to Virtual Interface features (VIFs).
  * 
  * @see VirtualInterfaceAsyncApi
  * @author Adam Lowe
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VIRTUAL_INTERFACES)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface VirtualInterfaceApi {
@@ -41,6 +44,6 @@
     *
     * @return the list of snapshots
     */
-   Set<? extends VirtualInterface> listVirtualInterfacesForServer(String serverId);   
+   FluentIterable<? extends VirtualInterface> listOnServer(String serverId);   
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceAsyncApi.java
index f37bf69..de94545 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -34,8 +32,10 @@
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -44,17 +44,18 @@
  * @see VirtualInterfaceApi
  * @author Adam Lowe
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VIRTUAL_INTERFACES)
 @SkipEncoding({'/', '='})
 @RequestFilters(AuthenticateRequest.class)
 public interface VirtualInterfaceAsyncApi {
    /**
-    * @see VirtualInterfaceApi#listVirtualInterfacesForServer(String)
+    * @see VirtualInterfaceApi#listOnServer(String)
     */
    @GET
    @SelectJson("virtual_interfaces")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/servers/{server_id}/os-virtual-interfaces")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends VirtualInterface>> listVirtualInterfacesForServer(@PathParam("server_id") String serverId);
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends VirtualInterface>> listOnServer(@PathParam("server_id") String serverId);
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApi.java
index 3e3af64..30f509f 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -30,13 +29,18 @@
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides synchronous access to Volumes.
  * <p/>
  * 
+ * @see VolumeAsyncApi
  * @see org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi
  * @author Adam Lowe
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUMES)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface VolumeApi {
@@ -45,42 +49,42 @@
     *
     * @return the list of snapshots
     */
-   Set<? extends Volume> listVolumes();
+   FluentIterable<? extends Volume> list();
 
    /**
     * Returns a detailed list of volumes.
     *
     * @return the list of volumes.
     */
-   Set<? extends Volume> listVolumesInDetail();
+   FluentIterable<? extends Volume> listInDetail();
 
    /**
     * Return data about the given volume.
     *
     * @return details of a specific snapshot.
     */
-   Volume getVolume(String volumeId);
+   Volume get(String volumeId);
 
    /**
     * Creates a new Snapshot
     *
     * @return the new Snapshot
     */
-   Volume createVolume(int sizeGB, CreateVolumeOptions... options);
+   Volume create(int sizeGB, CreateVolumeOptions... options);
 
    /**
     * Delete a snapshot.
     *
     * @return true if successful
     */
-   Boolean deleteVolume(String volumeId);
+   boolean delete(String volumeId);
    
    /**
     * List volume attachments for a given instance.
     * 
     * @return all Floating IPs
     */
-   Set<? extends VolumeAttachment> listAttachmentsOnServer(String serverId);
+   FluentIterable<? extends VolumeAttachment> listAttachmentsOnServer(String serverId);
 
    /**
     * Get a specific attached volume.
@@ -108,14 +112,14 @@
     *
     * @return the list of snapshots
     */
-   Set<? extends VolumeSnapshot> listSnapshots();
+   FluentIterable<? extends VolumeSnapshot> listSnapshots();
 
    /**
     * Returns a summary list of snapshots.
     *
     * @return the list of snapshots
     */
-   Set<? extends VolumeSnapshot> listSnapshotsInDetail();
+   FluentIterable<? extends VolumeSnapshot> listSnapshotsInDetail();
 
    /**
     * Return data about the given snapshot.
@@ -136,6 +140,6 @@
     *
     * @return true if successful
     */
-   Boolean deleteSnapshot(String snapshotId);
+   boolean deleteSnapshot(String snapshotId);
    
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeAsyncApi.java
index 412183a..d85bf68 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.extensions;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -44,10 +42,12 @@
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
 import org.jclouds.rest.annotations.WrapWith;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -57,6 +57,7 @@
  * @see org.jclouds.openstack.nova.v2_0.extensions.VolumeAsyncApi
  * @author Adam Lowe
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUMES)
 @SkipEncoding({'/', '='})
 @RequestFilters(AuthenticateRequest.class)
@@ -70,8 +71,8 @@
    @Path("/os-volumes")
    @SelectJson("volumes")
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Volume>> listVolumes();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends Volume>> list();
 
    /**
     * Returns a detailed list of volumes.
@@ -82,8 +83,8 @@
    @Path("/os-volumes/detail")
    @SelectJson("volumes")
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Volume>> listVolumesInDetail();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends Volume>> listInDetail();
 
    /**
     * Return data about the given volume.
@@ -95,7 +96,7 @@
    @SelectJson("volume")
    @Consumes(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends Volume> getVolume(@PathParam("id") String volumeId);
+   ListenableFuture<? extends Volume> get(@PathParam("id") String volumeId);
 
    /**
     * Creates a new volume
@@ -108,7 +109,7 @@
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @MapBinder(CreateVolumeOptions.class)
-   ListenableFuture<? extends Volume> createVolume(@PayloadParam("size") int sizeGB, CreateVolumeOptions... options);
+   ListenableFuture<? extends Volume> create(@PayloadParam("size") int sizeGB, CreateVolumeOptions... options);
 
    /**
     * Delete a volume.
@@ -119,7 +120,7 @@
    @Path("/os-volumes/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> deleteVolume(@PathParam("id") String volumeId);
+   ListenableFuture<Boolean> delete(@PathParam("id") String volumeId);
    
    /**
     * List volume attachments for a given instance.
@@ -130,8 +131,8 @@
    @Path("/servers/{server_id}/os-volume_attachments")
    @SelectJson("volumeAttachments")
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends VolumeAttachment>> listAttachmentsOnServer(@PathParam("server_id") String serverId);
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends VolumeAttachment>> listAttachmentsOnServer(@PathParam("server_id") String serverId);
 
    /**
     * Get a specific attached volume.
@@ -180,8 +181,8 @@
    @Path("/os-snapshots")
    @SelectJson("snapshots")
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends VolumeSnapshot>> listSnapshots();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends VolumeSnapshot>> listSnapshots();
 
    /**
     * Returns a summary list of snapshots.
@@ -192,8 +193,8 @@
    @Path("/os-snapshots/detail")
    @SelectJson("snapshots")
    @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends VolumeSnapshot>> listSnapshotsInDetail();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends VolumeSnapshot>> listSnapshotsInDetail();
 
    /**
     * Return data about the given snapshot.
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApi.java
index b1225c3..16d2950 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApi.java
@@ -19,16 +19,16 @@
 package org.jclouds.openstack.nova.v2_0.extensions;
 
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.nova.v2_0.domain.VolumeType;
 import org.jclouds.openstack.nova.v2_0.options.CreateVolumeTypeOptions;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.openstack.v2_0.services.Extension;
-import org.jclouds.rest.annotations.RequestFilters;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 
 /**
  * Provides synchronous access to Volume Type features
@@ -39,21 +39,21 @@
  * @see <a href="http://nova.openstack.org/api/nova.api.openstack.compute.contrib.volumetypes.html"/>
  * @see <a href="https://blueprints.launchpad.net/nova/+spec/volume-type"/>
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUME_TYPES)
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
-@RequestFilters(AuthenticateRequest.class)
 public interface VolumeTypeApi {
 
    /**
     * @return set of all volume types
     */
-   Set<? extends VolumeType> listVolumeTypes();
+   FluentIterable<? extends VolumeType> list();
 
    /**
     * @param id the id of the volume type to retrieve
     * @return the requested volume type
     */
-   VolumeType getVolumeType(String id);
+   VolumeType get(String id);
 
    /**
     * Creates a new volume type
@@ -62,23 +62,23 @@
     * @param options optional settings for the new volume type
     * @return the new volume type
     */
-   VolumeType createVolumeType(String name, CreateVolumeTypeOptions... options);
+   VolumeType create(String name, CreateVolumeTypeOptions... options);
 
    /**
     * Deletes a volume type
     */
-   Boolean deleteVolumeType(String id);
+   boolean delete(String id);
 
    /**
     * @param id the id of the volume type
     * @return the set of extra metadata for the flavor
     */
-   Map<String, String> getAllExtraSpecs(String id);
+   Map<String, String> getExtraSpecs(String id);
 
    /**
     * Creates or updates the extra metadata for a given flavor
     */
-   Boolean setAllExtraSpecs(String id, Map<String, String> specs);
+   boolean updateExtraSpecs(String id, Map<String, String> specs);
 
    /**
     * Retrieve a single extra spec value
@@ -95,7 +95,7 @@
     * @param key   the extra spec key (when creating ensure this does not include whitespace or other difficult characters)
     * @param value the new value to store associate with the key
     */
-   Boolean setExtraSpec(String id, String key, String value);
+   boolean updateExtraSpec(String id, String key, String value);
 
    /**
     * Deletes an existing extra spec
@@ -103,5 +103,5 @@
     * @param id  the id of the volume type
     * @param key the key of the extra spec to delete
     */
-   Boolean deleteExtraSpec(String id, String key);
+   boolean deleteExtraSpec(String id, String key);
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeAsyncApi.java
index e50e172..8dc6061 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeAsyncApi.java
@@ -19,7 +19,6 @@
 package org.jclouds.openstack.nova.v2_0.extensions;
 
 import java.util.Map;
-import java.util.Set;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -46,11 +45,13 @@
 import org.jclouds.rest.annotations.Unwrap;
 import org.jclouds.rest.annotations.WrapWith;
 import org.jclouds.rest.binders.BindToJsonPayload;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnEmptyMapOnNotFoundOr404;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -59,6 +60,7 @@
  * @author Adam Lowe
  * @see VolumeTypeApi
  */
+@Beta
 @Extension(of = ServiceType.COMPUTE, namespace = ExtensionNamespaces.VOLUME_TYPES)
 @SkipEncoding({'/', '='})
 @RequestFilters(AuthenticateRequest.class)
@@ -67,58 +69,58 @@
 public interface VolumeTypeAsyncApi {
 
    /**
-    * @see VolumeTypeApi#listVolumeTypes
+    * @see VolumeTypeApi#list
     */
    @GET
    @SelectJson("volume_types")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends VolumeType>> listVolumeTypes();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends VolumeType>> list();
 
 
    /**
-    * @see VolumeTypeApi#getVolumeType
+    * @see VolumeTypeApi#get
     */
    @GET
    @Path("/{id}")
    @SelectJson("volume_type")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends VolumeType> getVolumeType(@PathParam("id") String id);
+   ListenableFuture<? extends VolumeType> get(@PathParam("id") String id);
 
    /**
-    * @see VolumeTypeApi#createVolumeType
+    * @see VolumeTypeApi#create
     */
    @POST
    @SelectJson("volume_type")
    @Produces(MediaType.APPLICATION_JSON)
    @WrapWith("volume_type")
-   ListenableFuture<? extends VolumeType> createVolumeType(@PayloadParam("name") String name, CreateVolumeTypeOptions... options);
+   ListenableFuture<? extends VolumeType> create(@PayloadParam("name") String name, CreateVolumeTypeOptions... options);
 
    /**
-    * @see VolumeTypeApi#deleteVolumeType
+    * @see VolumeTypeApi#delete
     */
    @DELETE
    @Path("/{id}")
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> deleteVolumeType(@PathParam("id") String id);
+   ListenableFuture<Boolean> delete(@PathParam("id") String id);
 
    /**
-    * @see VolumeTypeApi#getAllExtraSpecs(String)
+    * @see VolumeTypeApi#getExtraSpecs(String)
     */
    @GET
    @SelectJson("extra_specs")
    @Path("/{id}/extra_specs")
    @ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
-   ListenableFuture<Map<String, String>> getAllExtraSpecs(@PathParam("id") String id);
+   ListenableFuture<Map<String, String>> getExtraSpecs(@PathParam("id") String id);
 
    /**
-    * @see VolumeTypeApi#setAllExtraSpecs(String, java.util.Map)
+    * @see VolumeTypeApi#updateExtraSpecs(String, java.util.Map)
     */
    @POST
    @Path("/{id}/extra_specs")
    @Produces(MediaType.APPLICATION_JSON)
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
    @MapBinder(BindToJsonPayload.class)
-   ListenableFuture<Boolean> setAllExtraSpecs(@PathParam("id") String id, @PayloadParam("extra_specs") Map<String, String> specs);
+   ListenableFuture<Boolean> updateExtraSpecs(@PathParam("id") String id, @PayloadParam("extra_specs") Map<String, String> specs);
 
    /**
     * @see VolumeTypeApi#getExtraSpec(String, String)
@@ -130,14 +132,14 @@
    ListenableFuture<String> getExtraSpec(@PathParam("id") String id, @PathParam("key") String key);
 
    /**
-    * @see VolumeTypeApi#setExtraSpec(String, String, String)
+    * @see VolumeTypeApi#updateExtraSpec(String, String, String)
     */
    @PUT
    @Path("/{id}/extra_specs/{key}")
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"{key}\":\"{value}\"%7D")
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
-   ListenableFuture<Boolean> setExtraSpec(@PathParam("id") String id,
+   ListenableFuture<Boolean> updateExtraSpec(@PathParam("id") String id,
                                           @PathParam("key") @PayloadParam("key") String key,
                                           @PayloadParam("value") String value);
 
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorApi.java
index 5eb5cc6..bfda028 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorApi.java
@@ -18,20 +18,22 @@
  */
 package org.jclouds.openstack.nova.v2_0.features;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.jclouds.collect.PagedIterable;
 import org.jclouds.concurrent.Timeout;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.nova.v2_0.domain.Flavor;
 import org.jclouds.openstack.v2_0.domain.Resource;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 
 /**
  * Provides asynchronous access to Flavors via their REST API.
  * <p/>
  * 
- * @see FlavorApi
+ * @see FlavorAsyncApi
  * @see <a href=
- *      "http://docs.openstack.org/api/openstack-compute/1.1/content/Flavors-d1e4180.html"
+ *      "http://docs.openstack.org/api/openstack-compute/2/content/List_Flavors-d1e4188.html"
  *      />
  * @author Jeremy Daggett
  */
@@ -43,14 +45,18 @@
     * 
     * @return all flavors (IDs, names, links)
     */
-   Set<? extends Resource> listFlavors();
+   PagedIterable<? extends Resource> list();
+
+   PaginatedCollection<? extends Resource> list(PaginationOptions options);
 
    /**
     * List all flavors (all details)
     * 
     * @return all flavors (all details)
     */
-   Set<? extends Flavor> listFlavorsInDetail();
+   PagedIterable<? extends Flavor> listInDetail();
+
+   PaginatedCollection<? extends Flavor> listInDetail(PaginationOptions options);
 
    /**
     * List details of the specified flavor
@@ -59,6 +65,6 @@
     *           id of the flavor
     * @return flavor or null if not found
     */
-   Flavor getFlavor(String id);
+   Flavor get(String id);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorAsyncApi.java
index 632f888..411acb5 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/FlavorAsyncApi.java
@@ -18,22 +18,28 @@
  */
 package org.jclouds.openstack.nova.v2_0.features;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.core.MediaType;
 
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.v2_0.functions.ReturnEmptyPaginatedCollectionOnNotFoundOr404;
 import org.jclouds.openstack.nova.v2_0.domain.Flavor;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseFlavorDetails;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseFlavors;
 import org.jclouds.openstack.v2_0.domain.Resource;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
 import com.google.common.util.concurrent.ListenableFuture;
@@ -44,43 +50,65 @@
  * 
  * @see FlavorApi
  * @see <a href=
- *      "http://docs.openstack.org/api/openstack-compute/1.1/content/Flavors-d1e4180.html"
- *      />
- * @author Jeremy Daggett TODO: Need a ListFlavorOptions class
- *         minDisk=minDiskInGB& minRam=minRamInMB& marker=markerID&limit=int
+ *      "http://docs.openstack.org/api/openstack-compute/2/content/List_Flavors-d1e4188.html"
+ *      >docs</a>
+ * @author Jeremy Daggett TODO: Need a ListFlavorOptions class minDisk=minDiskInGB&
+ *         minRam=minRamInMB& marker=markerID&limit=int
  */
 @SkipEncoding({ '/', '=' })
 @RequestFilters(AuthenticateRequest.class)
 public interface FlavorAsyncApi {
 
    /**
-    * @see FlavorApi#listFlavors
+    * @see FlavorApi#list()
     */
    @GET
-   @SelectJson("flavors")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/flavors")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Resource>> listFlavors();
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseFlavors.class)
+   @Transform(ParseFlavors.ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends Resource>> list();
+
+   /** @see FlavorApi#list(PaginationOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/flavors")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseFlavors.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends Resource>> list(PaginationOptions options);
 
    /**
-    * @see FlavorApi#listFlavorsInDetail
+    * @see FlavorApi#listInDetail()
     */
    @GET
-   @SelectJson("flavors")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/flavors/detail")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Flavor>> listFlavorsInDetail();
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseFlavorDetails.class)
+   @Transform(ParseFlavorDetails.ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends Flavor>> listInDetail();
+
+   /** @see FlavorApi#listInDetail(PaginationOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/flavors/detail")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseFlavorDetails.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends Flavor>> listInDetail(PaginationOptions options);
 
    /**
-    * @see FlavorApi#getFlavor
+    * @see FlavorApi#get
     */
    @GET
    @SelectJson("flavor")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/flavors/{id}")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends Flavor> getFlavor(@PathParam("id") String id);
+   ListenableFuture<? extends Flavor> get(@PathParam("id") String id);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ImageApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ImageApi.java
index 89fe3e3..5afb755 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ImageApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ImageApi.java
@@ -18,12 +18,16 @@
  */
 package org.jclouds.openstack.nova.v2_0.features;
 
-import java.util.Set;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
+import org.jclouds.collect.PagedIterable;
 import org.jclouds.concurrent.Timeout;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.nova.v2_0.domain.Image;
 import org.jclouds.openstack.v2_0.domain.Resource;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 
 /**
  * Provides synchronous access to Images.
@@ -43,14 +47,18 @@
     * 
     * @return all images (IDs, names, links)
     */
-   Set<? extends Resource> listImages();
+   PagedIterable<? extends Resource> list();
+
+   PaginatedCollection<? extends Resource> list(PaginationOptions options);
 
    /**
     * List all images (all details)
     * 
     * @return all images (all details)
     */
-   Set<? extends Image> listImagesInDetail();
+   PagedIterable<? extends Image> listInDetail();
+
+   PaginatedCollection<? extends Image> listInDetail(PaginationOptions options);
 
    /**
     * List details of the specified image
@@ -59,7 +67,7 @@
     *           id of the server
     * @return server or null if not found
     */
-   Image getImage(String id);
+   Image get(String id);
 
    /**
     * Delete the specified image
@@ -68,6 +76,73 @@
     *           id of the image
     * @return server or null if not found
     */
-   void deleteImage(String id);
+   void delete(String id);
+   
+   /**
+    * List all metadata for an image.
+    * 
+    * @param id
+    *           id of the image
+    * @return the metadata as a Map<String, String> 
+    */
+   Map<String, String> getMetadata(String id);
+
+   /**
+    * Sets the metadata for an image.
+    * 
+    * @param id
+    *           id of the image
+    * @param metadata
+    *           a Map containing the metadata
+    * @return the metadata as a Map<String, String> 
+    */
+   Map<String, String> setMetadata(String id, Map<String, String> metadata);
+
+   /**
+    * Update the metadata for a server.
+    * 
+    * @param id
+    *           id of the image
+    * @param metadata
+    *           a Map containing the metadata
+    * @return the metadata as a Map<String, String> 
+    */
+   Map<String, String> updateMetadata(String id, Map<String, String> metadata);
+   
+   /**
+    * Update the metadata for an image.
+    * 
+    * @param id
+    *           id of the image
+    * @param metadata
+    *           a Map containing the metadata
+    * @return the value or null if not present
+    */
+   @Nullable
+   String getMetadata(String id, String key);
+
+   
+   /**
+    * Set a metadata item for an image.
+    * 
+    * @param id
+    *           id of the image
+    * @param key
+    *           the name of the metadata item
+    * @param value
+    *           the value of the metadata item
+    * @return the value you updated
+    */
+   String updateMetadata(String id, String key, String value);
+
+   /**
+    * Delete a metadata item from an image.
+    * 
+    * @param id
+    *           id of the image
+    * @param key
+    *           the name of the metadata item
+    */
+   void deleteMetadata(String id, String key);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ImageAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ImageAsyncApi.java
index 40fbc94..0d69ab3 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ImageAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ImageAsyncApi.java
@@ -18,23 +18,40 @@
  */
 package org.jclouds.openstack.nova.v2_0.features;
 
-import java.util.Set;
+import java.util.Map;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.v2_0.functions.ReturnEmptyPaginatedCollectionOnNotFoundOr404;
+import org.jclouds.openstack.nova.v2_0.binders.BindMetadataToJsonPayload;
 import org.jclouds.openstack.nova.v2_0.domain.Image;
+import org.jclouds.openstack.nova.v2_0.functions.internal.OnlyMetadataValueOrNull;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseImageDetails;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseImages;
 import org.jclouds.openstack.v2_0.domain.Resource;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
 import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.binders.BindToJsonPayload;
+import org.jclouds.rest.functions.ReturnEmptyMapOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
 
@@ -52,42 +69,129 @@
 public interface ImageAsyncApi {
 
    /**
-    * @see ImageApi#listImages
+    * @see ImageApi#list()
     */
    @GET
-   @SelectJson("images")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/images")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Resource>> listImages();
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseImages.class)
+   @Transform(ParseImages.ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends Resource>> list();
+
+   /** @see ImageApi#list(PaginationOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/images")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseImages.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends Resource>> list(PaginationOptions options);
 
    /**
-    * @see ImageApi#listImagesInDetail
+    * @see ImageApi#listInDetail()
     */
    @GET
-   @SelectJson("images")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/images/detail")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Image>> listImagesInDetail();
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseImageDetails.class)
+   @Transform(ParseImageDetails.ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends Image>> listInDetail();
+
+   /** @see ImageApi#listInDetail(PaginationOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/images/detail")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseImageDetails.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends Image>> listInDetail(PaginationOptions options);
 
    /**
-    * @see ImageApi#getImage
+    * @see ImageApi#get
     */
    @GET
    @SelectJson("image")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/images/{id}")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends Image> getImage(@PathParam("id") String id);
+   ListenableFuture<? extends Image> get(@PathParam("id") String id);
 
    /**
-    * @see ImageApi#deleteImage
+    * @see ImageApi#delete
     */
    @DELETE
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/images/{id}")
    @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
-   ListenableFuture<Void> deleteImage(@PathParam("id") String id);
+   ListenableFuture<Void> delete(@PathParam("id") String id);
+   
+   /**
+    * @see ImageApi#getMetadata
+    */
+   @GET
+   @SelectJson("metadata")
+   @Path("/images/{id}/metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
+   ListenableFuture<Map<String, String>> getMetadata(@PathParam("id") String id);
 
+   /**
+    * @see ImageApi#setMetadata
+    */
+   @PUT
+   @SelectJson("metadata")
+   @Path("/images/{id}/metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Produces(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
+   @MapBinder(BindToJsonPayload.class)
+   ListenableFuture<Map<String, String>> setMetadata(@PathParam("id") String id, @PayloadParam("metadata") Map<String, String> metadata);
+
+   /**
+    * @see ImageApi#updateMetadata
+    */
+   @POST
+   @SelectJson("metadata")
+   @Path("/images/{id}/metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Produces(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
+   @MapBinder(BindToJsonPayload.class)
+   ListenableFuture<? extends Map<String, String>> updateMetadata(@PathParam("id") String id, @PayloadParam("metadata") Map<String, String> metadata);
+
+   /**
+    * @see ImageApi#getMetadata
+    */
+   @GET
+   @Path("/images/{id}/metadata/{key}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ResponseParser(OnlyMetadataValueOrNull.class)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<String> getMetadata(@PathParam("id") String id, @PathParam("key") String key);
+   
+   /**
+    * @see ImageApi#updateMetadata
+    */
+   @PUT
+   @Path("/images/{id}/metadata/{key}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Produces(MediaType.APPLICATION_JSON)
+   @ResponseParser(OnlyMetadataValueOrNull.class)
+   @MapBinder(BindMetadataToJsonPayload.class)
+   ListenableFuture<String> updateMetadata(@PathParam("id") String id,
+            @PathParam("key") @PayloadParam("key") String key, @PathParam("value") @PayloadParam("value") String value);
+
+   
+   /**
+    * @see ImageApi#deleteMetadata
+    */
+   @DELETE
+   @Consumes
+   @Path("/images/{id}/metadata/{key}")
+   @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
+   ListenableFuture<Void> deleteMetadata(@PathParam("id") String id, @PathParam("key") String key);
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
index 1378b18..f7ea8b2 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerApi.java
@@ -18,16 +18,20 @@
  */
 package org.jclouds.openstack.nova.v2_0.features;
 
-import java.util.Set;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
+import org.jclouds.collect.PagedIterable;
 import org.jclouds.concurrent.Timeout;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.nova.v2_0.domain.RebootType;
 import org.jclouds.openstack.nova.v2_0.domain.Server;
 import org.jclouds.openstack.nova.v2_0.domain.ServerCreated;
 import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
 import org.jclouds.openstack.nova.v2_0.options.RebuildServerOptions;
 import org.jclouds.openstack.v2_0.domain.Resource;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 
 /**
  * Provides synchronous access to Server.
@@ -47,14 +51,18 @@
     * 
     * @return all servers (IDs, names, links)
     */
-   Set<? extends Resource> listServers();
+   PagedIterable<? extends Resource> list();
+
+   PaginatedCollection<? extends Resource> list(PaginationOptions options);
 
    /**
     * List all servers (all details)
     * 
     * @return all servers (all details)
     */
-   Set<? extends Server> listServersInDetail();
+   PagedIterable<? extends Server> listInDetail();
+
+   PaginatedCollection<? extends Server> listInDetail(PaginationOptions options);
 
    /**
     * List details of the specified server
@@ -63,7 +71,7 @@
     *           id of the server
     * @return server or null if not found
     */
-   Server getServer(String id);
+   Server get(String id);
 
    /**
     * Create a new server
@@ -81,7 +89,7 @@
     */
    // blocking call
    @Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
-   ServerCreated createServer(String name, String imageRef, String flavorRef, CreateServerOptions... options);
+   ServerCreated create(String name, String imageRef, String flavorRef, CreateServerOptions... options);
 
    /**
     * Terminate and delete a server.
@@ -90,7 +98,7 @@
     *           id of the server
     * @return True if successful, False otherwise
     */
-   Boolean deleteServer(String id);
+   boolean delete(String id);
   
    /**
     * Start a server
@@ -98,7 +106,7 @@
     * @param id
     *           id of the server
     */
-   void startServer(String id);
+   void start(String id);
 
    /**
     * Stop a server
@@ -106,7 +114,7 @@
     * @param id
     *           id of the server
     */
-   void stopServer(String id);
+   void stop(String id);
    
    /**
     * Reboot a server.
@@ -116,7 +124,7 @@
     * @param rebootType
     *           The type of reboot to perform (Hard/Soft)
     */
-   void rebootServer(String id, RebootType rebootType);
+   void reboot(String id, RebootType rebootType);
 
    /**
     * Resize a server to a new flavor size.
@@ -126,7 +134,7 @@
     * @param flavorId
     *           id of the new flavor to use
     */
-   void resizeServer(String id, String flavorId);
+   void resize(String id, String flavorId);
 
    /**
     * Confirm a resize operation.
@@ -134,7 +142,7 @@
     * @param id
     *           id of the server
     */
-   void confirmResizeServer(String id);
+   void confirmResize(String id);
 
    /**
     * Revert a resize operation.
@@ -142,7 +150,7 @@
     * @param id
     *           id of the server
     */
-   void revertResizeServer(String id);
+   void revertResize(String id);
 
    /**
     * Rebuild a server.
@@ -152,7 +160,7 @@
     * @param options
     *           Optional parameters to the rebuilding operation.
     */
-   void rebuildServer(String id, RebuildServerOptions... options);
+   void rebuild(String id, RebuildServerOptions... options);
 
    /**
     * Change the administrative password to a server.
@@ -172,7 +180,7 @@
     * @param newName
     *           The new name for the server
     */
-   void renameServer(String id, String newName);
+   void rename(String id, String newName);
 
    /**
     * Create an image from a server.
@@ -185,5 +193,72 @@
     * @return ID of the new / updated image
     */
    String createImageFromServer(String name, String id);
+   
+   /**
+    * List all metadata for a server.
+    * 
+    * @param id
+    *           id of the server
+    *                      
+    * @return the metadata as a Map<String, String> 
+    */
+   Map<String, String> getMetadata(String id);
+
+   /**
+    * Set the metadata for a server.
+    * 
+    * @param id
+    *           id of the server
+    * @param metadata
+    *           a Map containing the metadata
+    * @return the metadata as a Map<String, String> 
+    */
+   Map<String, String> setMetadata(String id, Map<String, String> metadata);
+   
+   /**
+    * Update the metadata for a server.
+    * 
+    * @param id
+    *           id of the server
+    * @param metadata
+    *           a Map containing the metadata
+    * @return the metadata as a Map<String, String> 
+    */
+   Map<String, String> updateMetadata(String id, Map<String, String> metadata);
+   
+   /**
+    * Update the metadata for a server.
+    * 
+    * @param id
+    *           id of the image
+    * @param metadata
+    *           a Map containing the metadata
+    * @return the value or null if not present
+    */
+   @Nullable
+   String getMetadata(String id, String key);
+
+   /**
+    * Set a metadata item for a server.
+    * 
+    * @param id
+    *           id of the image
+    * @param key
+    *           the name of the metadata item
+    * @param value
+    *           the value of the metadata item
+    * @return the value you updated
+    */
+   String updateMetadata(String id, String key, String value);
+
+   /**
+    * Delete a metadata item from a server.
+    * 
+    * @param id
+    *           id of the image
+    * @param key
+    *           the name of the metadata item
+    */
+   void deleteMetadata(String id, String key);
 
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerAsyncApi.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerAsyncApi.java
index c1d7a7b..ef30707 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerAsyncApi.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/features/ServerAsyncApi.java
@@ -18,7 +18,7 @@
  */
 package org.jclouds.openstack.nova.v2_0.features;
 
-import java.util.Set;
+import java.util.Map;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -30,14 +30,22 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.v2_0.functions.ReturnEmptyPaginatedCollectionOnNotFoundOr404;
+import org.jclouds.openstack.nova.v2_0.binders.BindMetadataToJsonPayload;
 import org.jclouds.openstack.nova.v2_0.domain.RebootType;
 import org.jclouds.openstack.nova.v2_0.domain.Server;
 import org.jclouds.openstack.nova.v2_0.domain.ServerCreated;
 import org.jclouds.openstack.nova.v2_0.functions.ParseImageIdFromLocationHeader;
+import org.jclouds.openstack.nova.v2_0.functions.internal.OnlyMetadataValueOrNull;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseServerDetails;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseServers;
 import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
 import org.jclouds.openstack.nova.v2_0.options.RebuildServerOptions;
 import org.jclouds.openstack.v2_0.domain.Resource;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.MapBinder;
 import org.jclouds.rest.annotations.Payload;
@@ -46,11 +54,15 @@
 import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.annotations.Transform;
 import org.jclouds.rest.annotations.Unwrap;
+import org.jclouds.rest.binders.BindToJsonPayload;
 import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyMapOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -59,8 +71,7 @@
  * <p/>
  * 
  * @see ServerApi
- * @see <a href=
- *      "http://docs.openstack.org/api/openstack-compute/1.1/content/Servers-d1e2073.html"
+ * @see <a href= "http://docs.openstack.org/api/openstack-compute/1.1/content/Servers-d1e2073.html"
  *      />
  * @author Adrian Cole
  */
@@ -69,123 +80,145 @@
 public interface ServerAsyncApi {
 
    /**
-    * @see ServerApi#listServers
+    * @see ServerApi#list()
     */
    @GET
-   @SelectJson("servers")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/servers")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Resource>> listServers();
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseServers.class)
+   @Transform(ParseServers.ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends Resource>> list();
+
+   /** @see ServerApi#list(PaginationOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/servers")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseServers.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends Resource>> list(PaginationOptions options);
 
    /**
-    * @see ServerApi#listServersInDetail
+    * @see ServerApi#listInDetail()
     */
    @GET
-   @SelectJson("servers")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/servers/detail")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Server>> listServersInDetail();
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseServerDetails.class)
+   @Transform(ParseServerDetails.ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends Server>> listInDetail();
+
+   /** @see ServerApi#listInDetail(PaginationOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/servers/detail")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseServerDetails.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends Server>> listInDetail(PaginationOptions options);
 
    /**
-    * @see ServerApi#getServer
+    * @see ServerApi#get
     */
    @GET
    @SelectJson("server")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/servers/{id}")
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<? extends Server> getServer(@PathParam("id") String id);
+   ListenableFuture<? extends Server> get(@PathParam("id") String id);
 
    /**
-    * @see ServerApi#deleteServer
+    * @see ServerApi#delete
     */
    @DELETE
    @Consumes
    @ExceptionParser(ReturnFalseOnNotFoundOr404.class)
    @Path("/servers/{id}")
-   ListenableFuture<Boolean> deleteServer(@PathParam("id") String id);
+   ListenableFuture<Boolean> delete(@PathParam("id") String id);
 
    /**
-    * @see ServerApi#startServer
+    * @see ServerApi#start
     */
    @POST
    @Path("/servers/{id}/action")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("{\"os-start\":null}")
-   ListenableFuture<Void> startServer(@PathParam("id") String id);
+   ListenableFuture<Void> start(@PathParam("id") String id);
 
    /**
-    * @see ServerApi#stopServer
+    * @see ServerApi#stop
     */
    @POST
    @Path("/servers/{id}/action")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("{\"os-stop\":null}")
-   ListenableFuture<Void> stopServer(@PathParam("id") String id);
-   
+   ListenableFuture<Void> stop(@PathParam("id") String id);
+
    /**
-    * @see ServerApi#rebootServer
+    * @see ServerApi#reboot
     */
    @POST
    @Path("/servers/{id}/action")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"reboot\":%7B\"type\":\"{type}\"%7D%7D")
-   ListenableFuture<Void> rebootServer(@PathParam("id") String id, @PayloadParam("type") RebootType rebootType);
+   ListenableFuture<Void> reboot(@PathParam("id") String id, @PayloadParam("type") RebootType rebootType);
 
    /**
-    * @see ServerApi#resizeServer
+    * @see ServerApi#resize
     */
    @POST
    @Path("/servers/{id}/action")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"resize\":%7B\"flavorRef\":{flavorId}%7D%7D")
-   ListenableFuture<Void> resizeServer(@PathParam("id") String id, @PayloadParam("flavorId") String flavorId);
+   ListenableFuture<Void> resize(@PathParam("id") String id, @PayloadParam("flavorId") String flavorId);
 
    /**
-    * @see ServerApi#confirmResizeServer
+    * @see ServerApi#confirmResize
     */
    @POST
    @Path("/servers/{id}/action")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("{\"confirmResize\":null}")
-   ListenableFuture<Void> confirmResizeServer(@PathParam("id") String id);
+   ListenableFuture<Void> confirmResize(@PathParam("id") String id);
 
    /**
-    * @see ServerApi#revertResizeServer
+    * @see ServerApi#revertResize
     */
    @POST
    @Path("/servers/{id}/action")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("{\"revertResize\":null}")
-   ListenableFuture<Void> revertResizeServer(@PathParam("id") String id);
+   ListenableFuture<Void> revertResize(@PathParam("id") String id);
 
    /**
-    * @see ServerApi#createServer
+    * @see ServerApi#create
     */
    @POST
    @Unwrap
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/servers")
    @MapBinder(CreateServerOptions.class)
-   ListenableFuture<ServerCreated> createServer(@PayloadParam("name") String name, @PayloadParam("imageRef") String imageRef,
-         @PayloadParam("flavorRef") String flavorRef, CreateServerOptions... options);
+   ListenableFuture<ServerCreated> create(@PayloadParam("name") String name, @PayloadParam("imageRef") String imageRef,
+            @PayloadParam("flavorRef") String flavorRef, CreateServerOptions... options);
 
    /**
-    * @see ServerApi#rebuildServer
+    * @see ServerApi#rebuild
     */
    @POST
    @Path("/servers/{id}/action")
    @Consumes
    @MapBinder(RebuildServerOptions.class)
-   ListenableFuture<Void> rebuildServer(@PathParam("id") String id, RebuildServerOptions... options);
+   ListenableFuture<Void> rebuild(@PathParam("id") String id, RebuildServerOptions... options);
 
    /**
     * @see ServerApi#changeAdminPass
@@ -198,14 +231,14 @@
    ListenableFuture<Void> changeAdminPass(@PathParam("id") String id, @PayloadParam("adminPass") String adminPass);
 
    /**
-    * @see ServerApi#renameServer
+    * @see ServerApi#rename
     */
    @PUT
    @Path("/servers/{id}")
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    @Payload("%7B\"server\":%7B\"name\":\"{name}\"%7D%7D")
-   ListenableFuture<Void> renameServer(@PathParam("id") String id, @PayloadParam("name") String newName);
+   ListenableFuture<Void> rename(@PathParam("id") String id, @PayloadParam("name") String newName);
 
    /**
     * @see ServerApi#createImageFromServer
@@ -219,4 +252,71 @@
    @ResponseParser(ParseImageIdFromLocationHeader.class)
    ListenableFuture<String> createImageFromServer(@PayloadParam("name") String name, @PathParam("id") String id);
 
+   /**
+    * @see ServerApi#getMetadata
+    */
+   @GET
+   @SelectJson("metadata")
+   @Path("/servers/{id}/metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
+   ListenableFuture<? extends Map<String, String>> getMetadata(@PathParam("id") String id);
+
+   /**
+    * @see ServerApi#setMetadata
+    */
+   @PUT
+   @SelectJson("metadata")
+   @Path("/servers/{id}/metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Produces(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
+   @MapBinder(BindToJsonPayload.class)
+   ListenableFuture<? extends Map<String, String>> setMetadata(@PathParam("id") String id,
+            @PayloadParam("metadata") Map<String, String> metadata);
+
+   /**
+    * @see ServerApi#updateMetadata
+    */
+   @POST
+   @SelectJson("metadata")
+   @Path("/servers/{id}/metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Produces(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyMapOnNotFoundOr404.class)
+   @MapBinder(BindToJsonPayload.class)
+   ListenableFuture<? extends Map<String, String>> updateMetadata(@PathParam("id") String id,
+            @PayloadParam("metadata") Map<String, String> metadata);
+
+   /**
+    * @see ServerApi#getMetadata
+    */
+   @GET
+   @Path("/servers/{id}/metadata/{key}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ResponseParser(OnlyMetadataValueOrNull.class)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<String> getMetadata(@PathParam("id") String id, @PathParam("key") String key);
+
+   /**
+    * @see ServerApi#updateMetadata
+    */
+   @PUT
+   @Path("/servers/{id}/metadata/{key}")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Produces(MediaType.APPLICATION_JSON)
+   @ResponseParser(OnlyMetadataValueOrNull.class)
+   @MapBinder(BindMetadataToJsonPayload.class)
+   ListenableFuture<String> updateMetadata(@PathParam("id") String id,
+            @PathParam("key") @PayloadParam("key") String key, @PathParam("value") @PayloadParam("value") String value);
+
+   /**
+    * @see ServerApi#deleteMetadata
+    */
+   @DELETE
+   @Consumes
+   @Path("/servers/{id}/metadata/{key}")
+   @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
+   ListenableFuture<Void> deleteMetadata(@PathParam("id") String id, @PathParam("key") String key);
+
 }
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/OnlyMetadataValueOrNull.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/OnlyMetadataValueOrNull.java
new file mode 100644
index 0000000..d00c2e7
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/OnlyMetadataValueOrNull.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.internal.GsonWrapper;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Singleton
+public class OnlyMetadataValueOrNull implements Function<HttpResponse, String> {
+   private final ParseJson<Wrapper> parser;
+
+   private static class Wrapper implements Supplier<String> {
+      private Map<String, String> metadata;
+
+      @Override
+      public String get() {
+         return metadata == null ? null : Iterables.get(metadata.values(), 0, null);
+      }
+
+   }
+
+   @Inject
+   public OnlyMetadataValueOrNull(GsonWrapper gsonView) {
+      this.parser = new ParseJson<Wrapper>(checkNotNull(gsonView, "gsonView"), new TypeLiteral<Wrapper>() {
+      });
+   }
+
+   public String apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      return parser.apply(response).get();
+   }
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseFlavorDetails.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseFlavorDetails.java
new file mode 100644
index 0000000..45354e0
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseFlavorDetails.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.domain.Flavor;
+import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseFlavorDetails.Flavors;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseFlavorDetails extends ParseJson<Flavors<? extends Flavor>> {
+   static class Flavors<T extends Flavor> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "flavors", "flavors_links" })
+      protected Flavors(Iterable<T> flavors, Iterable<Link> flavors_links) {
+         super(flavors, flavors_links);
+      }
+
+   }
+
+   @Inject
+   public ParseFlavorDetails(Json json) {
+      super(json, new TypeLiteral<Flavors<? extends Flavor>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<Flavor, ToPagedIterable> {
+
+      private final NovaApi api;
+
+      @Inject
+      protected ToPagedIterable(NovaApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<Flavor>> markerToNextForCallingArg0(final String zone) {
+         final FlavorApi flavorApi = api.getFlavorApiForZone(zone);
+         return new Function<Object, IterableWithMarker<Flavor>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<Flavor> apply(Object input) {
+               return IterableWithMarker.class.cast(flavorApi.listInDetail(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "listFlavorsInDetail()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseFlavors.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseFlavors.java
new file mode 100644
index 0000000..fd28914
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseFlavors.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseFlavors.Flavors;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Resource;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseFlavors extends ParseJson<Flavors<? extends Resource>> {
+   static class Flavors<T extends Resource> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "flavors", "flavors_links" })
+      protected Flavors(Iterable<T> flavors, Iterable<Link> flavors_links) {
+         super(flavors, flavors_links);
+      }
+
+   }
+
+   @Inject
+   public ParseFlavors(Json json) {
+      super(json, new TypeLiteral<Flavors<? extends Resource>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<Resource, ToPagedIterable> {
+
+      private final NovaApi api;
+
+      @Inject
+      protected ToPagedIterable(NovaApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<Resource>> markerToNextForCallingArg0(final String zone) {
+         final FlavorApi flavorApi = api.getFlavorApiForZone(zone);
+         return new Function<Object, IterableWithMarker<Resource>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<Resource> apply(Object input) {
+               return IterableWithMarker.class.cast(flavorApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "listFlavors()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseImageDetails.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseImageDetails.java
new file mode 100644
index 0000000..225e9f1
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseImageDetails.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.domain.Image;
+import org.jclouds.openstack.nova.v2_0.features.ImageApi;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseImageDetails.Images;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseImageDetails extends ParseJson<Images<? extends Image>> {
+   static class Images<T extends Image> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "images", "images_links" })
+      protected Images(Iterable<T> images, Iterable<Link> images_links) {
+         super(images, images_links);
+      }
+
+   }
+
+   @Inject
+   public ParseImageDetails(Json json) {
+      super(json, new TypeLiteral<Images<? extends Image>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<Image, ToPagedIterable> {
+
+      private final NovaApi api;
+
+      @Inject
+      protected ToPagedIterable(NovaApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<Image>> markerToNextForCallingArg0(final String zone) {
+         final ImageApi imageApi = api.getImageApiForZone(zone);
+         return new Function<Object, IterableWithMarker<Image>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<Image> apply(Object input) {
+               return IterableWithMarker.class.cast(imageApi.listInDetail(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "listInDetail()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseImages.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseImages.java
new file mode 100644
index 0000000..51680f7
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseImages.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.features.ImageApi;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseImages.Images;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Resource;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseImages extends ParseJson<Images<? extends Resource>> {
+   static class Images<T extends Resource> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "images", "images_links" })
+      protected Images(Iterable<T> images, Iterable<Link> images_links) {
+         super(images, images_links);
+      }
+
+   }
+
+   @Inject
+   public ParseImages(Json json) {
+      super(json, new TypeLiteral<Images<? extends Resource>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<Resource, ToPagedIterable> {
+
+      private final NovaApi api;
+
+      @Inject
+      protected ToPagedIterable(NovaApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<Resource>> markerToNextForCallingArg0(final String zone) {
+         final ImageApi imageApi = api.getImageApiForZone(zone);
+         return new Function<Object, IterableWithMarker<Resource>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<Resource> apply(Object input) {
+               return IterableWithMarker.class.cast(imageApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseKeyPairs.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseKeyPairs.java
new file mode 100644
index 0000000..1f4d54a
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseKeyPairs.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.json.internal.GsonWrapper;
+import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.FluentIterable;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Singleton
+public class ParseKeyPairs implements Function<HttpResponse, FluentIterable<? extends KeyPair>> {
+   private final ParseFirstJsonValueNamed<FluentIterable<Wrapper>> parser;
+
+   private static class Wrapper implements Supplier<KeyPair> {
+      private KeyPair keypair;
+
+      @Override
+      public KeyPair get() {
+         return keypair;
+      }
+
+   }
+
+   @Inject
+   public ParseKeyPairs(GsonWrapper gsonView) {
+      this.parser = new ParseFirstJsonValueNamed<FluentIterable<Wrapper>>(checkNotNull(gsonView, "gsonView"),
+               new TypeLiteral<FluentIterable<Wrapper>>() {
+               }, "keypairs");
+   }
+
+   public FluentIterable<? extends KeyPair> apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      return parser.apply(response).transform(Suppliers.<KeyPair> supplierFunction());
+   }
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseServerDetails.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseServerDetails.java
new file mode 100644
index 0000000..588d99d
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseServerDetails.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.domain.Server;
+import org.jclouds.openstack.nova.v2_0.features.ServerApi;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseServerDetails.Servers;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseServerDetails extends ParseJson<Servers<? extends Server>> {
+   static class Servers<T extends Server> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "servers", "servers_links" })
+      protected Servers(Iterable<T> servers, Iterable<Link> servers_links) {
+         super(servers, servers_links);
+      }
+
+   }
+
+   @Inject
+   public ParseServerDetails(Json json) {
+      super(json, new TypeLiteral<Servers<? extends Server>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<Server, ToPagedIterable> {
+
+      private final NovaApi api;
+
+      @Inject
+      protected ToPagedIterable(NovaApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<Server>> markerToNextForCallingArg0(final String zone) {
+         final ServerApi serverApi = api.getServerApiForZone(zone);
+         return new Function<Object, IterableWithMarker<Server>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<Server> apply(Object input) {
+               return IterableWithMarker.class.cast(serverApi.listInDetail(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "listInDetail()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseServers.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseServers.java
new file mode 100644
index 0000000..fb8d05d
--- /dev/null
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/functions/internal/ParseServers.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.v2_0.options.PaginationOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.nova.v2_0.NovaApi;
+import org.jclouds.openstack.nova.v2_0.features.ServerApi;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseServers.Servers;
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.Resource;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseServers extends ParseJson<Servers<? extends Resource>> {
+   static class Servers<T extends Resource> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "servers", "servers_links" })
+      protected Servers(Iterable<T> servers, Iterable<Link> servers_links) {
+         super(servers, servers_links);
+      }
+
+   }
+
+   @Inject
+   public ParseServers(Json json) {
+      super(json, new TypeLiteral<Servers<? extends Resource>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<Resource, ToPagedIterable> {
+
+      private final NovaApi api;
+
+      @Inject
+      protected ToPagedIterable(NovaApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<Resource>> markerToNextForCallingArg0(final String zone) {
+         final ServerApi serverApi = api.getServerApiForZone(zone);
+         return new Function<Object, IterableWithMarker<Resource>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<Resource> apply(Object input) {
+               return IterableWithMarker.class.cast(serverApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateBackupOfServerOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateBackupOfServerOptions.java
index 93ed756..b56eea2 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateBackupOfServerOptions.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateBackupOfServerOptions.java
@@ -55,7 +55,7 @@
 
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
-      throw new IllegalStateException("createBackupOfServer is a POST operation");
+      throw new IllegalStateException("createBackup is a POST operation");
    }
 
    @Override
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java
index 4acf359..db2bbed 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/CreateServerOptions.java
@@ -152,7 +152,7 @@
       return string().toString();
    }
 
-   private class ServerRequest {
+   static class ServerRequest {
       final String name;
       final String imageRef;
       final String flavorRef;
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/ListOptions.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/ListOptions.java
index 8cd271c..4d8fa91 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/ListOptions.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/options/ListOptions.java
@@ -20,16 +20,16 @@
 
 import java.util.Date;
 
-import org.jclouds.openstack.v2_0.options.BaseListOptions;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 
 /**
  * Options used to control the amount of detail in the request.
  * 
- * @see BaseListOptions
+ * @see PaginationOptions
  * @see <a href="http://wiki.openstack.org/OpenStackAPI_1-1" />
  * @author Adrian Cole
  */
-public class ListOptions extends BaseListOptions {
+public class ListOptions extends PaginationOptions {
 
    public static final ListOptions NONE = new ListOptions();
 
@@ -56,8 +56,8 @@
     * {@inheritDoc}
     */
    @Override
-   public ListOptions maxResults(int limit) {
-      super.maxResults(limit);
+   public ListOptions limit(int limit) {
+      super.limit(limit);
       return this;
 
    }
@@ -66,8 +66,8 @@
     * {@inheritDoc}
     */
    @Override
-   public ListOptions startAt(long offset) {
-      super.startAt(offset);
+   public ListOptions marker(String marker) {
+      super.marker(marker);
       return this;
    }
 
@@ -82,23 +82,23 @@
       }
 
       /**
-       * @see BaseListOptions#startAt(long)
+       * @see PaginationOptions#marker(String)
        */
-      public static ListOptions startAt(long prefix) {
+      public static ListOptions marker(String marker) {
          ListOptions options = new ListOptions();
-         return options.startAt(prefix);
+         return options.marker(marker);
       }
 
       /**
-       * @see BaseListOptions#maxResults(long)
+       * @see PaginationOptions#limit(long)
        */
       public static ListOptions maxResults(int maxKeys) {
          ListOptions options = new ListOptions();
-         return options.maxResults(maxKeys);
+         return options.limit(maxKeys);
       }
 
       /**
-       * @see BaseListOptions#changesSince(Date)
+       * @see PaginationOptions#changesSince(Date)
        */
       public static ListOptions changesSince(Date since) {
          ListOptions options = new ListOptions();
diff --git a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/FindSecurityGroupWithNameAndReturnTrue.java b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/FindSecurityGroupWithNameAndReturnTrue.java
index 0c435e3..bf4f1ad 100644
--- a/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/FindSecurityGroupWithNameAndReturnTrue.java
+++ b/apis/openstack-nova/src/main/java/org/jclouds/openstack/nova/v2_0/predicates/FindSecurityGroupWithNameAndReturnTrue.java
@@ -67,7 +67,7 @@
 
       logger.trace("looking for security group %s", securityGroupInZone.slashEncode());
       try {
-         SecurityGroup returnVal = Iterables.find(api.get().listSecurityGroups(), new Predicate<SecurityGroup>() {
+         SecurityGroup returnVal = Iterables.find(api.get().list(), new Predicate<SecurityGroup>() {
 
             @Override
             public boolean apply(SecurityGroup input) {
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAndTenantIdAuthenticationExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAndTenantIdAuthenticationExpectTest.java
index 41ec150..3abe926 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAndTenantIdAuthenticationExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAndTenantIdAuthenticationExpectTest.java
@@ -70,7 +70,7 @@
 

       assertEquals(apiWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));

 

-      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").listServers().toString(),

+      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").list().concat().toString(),

             new ParseServerListTest().expected().toString());

    }

 

diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest.java
index 0c113d0..c19cc00 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest.java
@@ -37,7 +37,7 @@
  * @see KeystoneProperties#CREDENTIAL_TYPE

  * @author Adrian Cole

  */

-@Test(groups = "unit", testName = "AccessKeyAndSecretKeyAndTenantIdAuthenticationExpectTest")

+@Test(groups = "unit", testName = "AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest")

 public class AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest extends BaseNovaApiExpectTest {

    public AccessKeyAndSecretKeyAndTenantNamePropertyAuthenticationExpectTest() {

       identity = "identity";

@@ -70,7 +70,7 @@
 

       assertEquals(apiWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));

 

-      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").listServers().toString(),

+      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").list().concat().toString(),

             new ParseServerListTest().expected().toString());

    }

 

diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAuthenticationExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAuthenticationExpectTest.java
index 3e737e0..eee0154 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAuthenticationExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/AccessKeyAndSecretKeyAuthenticationExpectTest.java
@@ -65,7 +65,7 @@
 

       assertEquals(apiWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));

 

-      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").listServers().toString(),

+      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").list().concat().toString(),

             new ParseServerListTest().expected().toString());

    }

 

diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/NovaErrorHandlerTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/NovaErrorHandlerTest.java
index ec16e85..2691715 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/NovaErrorHandlerTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/NovaErrorHandlerTest.java
@@ -81,7 +81,7 @@
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/os-floating-ips"),
                400,
                "HTTP/1.1 400 Bad Request",
-               "{\"badRequest\": {\"message\": \"AddressLimitExceeded: Address quota exceeded. You cannot allocate any more addresses\", \"code\": 400}}",
+               "{\"badRequest\": {\"message\": \"AddressLimitExceeded: Address quota exceeded. You cannot create any more addresses\", \"code\": 400}}",
                InsufficientResourcesException.class);
    }
    
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/PasswordAuthenticationExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/PasswordAuthenticationExpectTest.java
index 51c6815..d3b6c41 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/PasswordAuthenticationExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/PasswordAuthenticationExpectTest.java
@@ -56,7 +56,7 @@
 
       assertEquals(apiWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").listServers().toString(),
+      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").list().concat().toString(),
             new ParseServerListTest().expected().toString());
    }
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/PasswordAuthenticationWithTenantNameExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/PasswordAuthenticationWithTenantNameExpectTest.java
index ad19ef2..2e63e91 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/PasswordAuthenticationWithTenantNameExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/PasswordAuthenticationWithTenantNameExpectTest.java
@@ -65,7 +65,7 @@
 
       assertEquals(apiWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").listServers().toString(),
+      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").list().concat().toString(),
             new ParseServerListTest().expected().toString());
    }
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
index 3b2e6f4..48ff068 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceAdapterExpectTest.java
@@ -79,7 +79,7 @@
       Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
                .put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
                .put(extensionsOfNovaRequest, extensionsOfNovaResponse)
-               .put(listImagesDetail, listImagesDetailResponse)
+               .put(listDetail, listDetailResponse)
                .put(listFlavorsDetail, listFlavorsDetailResponse)
                .put(createServer, createServerResponse)
                .put(serverDetail, serverDetailResponse).build();
@@ -131,7 +131,7 @@
       Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
                .put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
                .put(extensionsOfNovaRequest, extensionsOfNovaResponse)
-               .put(listImagesDetail, listImagesDetailResponse)
+               .put(listDetail, listDetailResponse)
                .put(listFlavorsDetail, listFlavorsDetailResponse)
                .put(createServer, createServerResponse)
                .put(serverDetail, serverDetailResponse).build();
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java
index b29a11f..37abcd0 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/NovaComputeServiceExpectTest.java
@@ -57,7 +57,7 @@
 
       Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
             .put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
-            .put(extensionsOfNovaRequest, extensionsOfNovaResponse).put(listImagesDetail, listImagesDetailResponse)
+            .put(extensionsOfNovaRequest, extensionsOfNovaResponse).put(listDetail, listDetailResponse)
             .put(listServers, listServersResponse).put(listFlavorsDetail, listFlavorsDetailResponse).build();
 
       ComputeService apiWhenServersExist = requestsSendResponses(requestResponseMap);
@@ -88,7 +88,7 @@
                .endpoint("https://nova-api.trystack.org:9774/v1.1/3456/extensions").build(),
                HttpResponse.builder().statusCode(200).payload(payloadFromResource("/extension_list_trystack.json"))
                      .build())
-         .put(listImagesDetail.toBuilder()
+         .put(listDetail.toBuilder()
                .endpoint("https://nova-api.trystack.org:9774/v1.1/3456/images/detail").build(),
                HttpResponse.builder().statusCode(200).payload(payloadFromResource("/image_list_detail_trystack.json"))
                      .build())
@@ -135,7 +135,7 @@
       assertTrue(apiWhenNoServersExist.listNodes().isEmpty());
    }
 
-   HttpRequest listSecurityGroups = HttpRequest
+   HttpRequest list = HttpRequest
          .builder()
          .method("GET")
          .endpoint("https://nova-api.trystack.org:9774/v1.1/3456/os-security-groups")
@@ -144,7 +144,7 @@
 
    HttpResponse notFound = HttpResponse.builder().statusCode(404).build();
 
-   HttpRequest createSecurityGroupWithPrefixOnGroup = HttpRequest
+   HttpRequest createWithPrefixOnGroup = HttpRequest
          .builder()
          .method("POST")
          .endpoint("https://nova-api.trystack.org:9774/v1.1/3456/os-security-groups")
@@ -158,7 +158,7 @@
    HttpResponse securityGroupCreated = HttpResponse.builder().statusCode(200)
          .payload(payloadFromResource("/securitygroup_created.json")).build();
 
-   HttpRequest createSecurityGroupRuleForDefaultPort22 = HttpRequest
+   HttpRequest createRuleForDefaultPort22 = HttpRequest
          .builder()
          .method("POST")
          .endpoint("https://nova-api.trystack.org:9774/v1.1/3456/os-security-group-rules")
@@ -182,7 +182,7 @@
    HttpResponse securityGroupWithPort22 = HttpResponse.builder().statusCode(200)
          .payload(payloadFromResource("/securitygroup_details_port22.json")).build();
    
-   HttpRequest createKeyPair = HttpRequest
+   HttpRequest create = HttpRequest
          .builder()
          .method("POST")
          .endpoint("https://nova-api.trystack.org:9774/v1.1/3456/os-keypairs")
@@ -210,15 +210,15 @@
    public void testCreateNodeWithGeneratedKeyPair() throws Exception {
       Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
             .putAll(defaultTemplateTryStack);
-      requestResponseMap.put(listSecurityGroups, notFound);
+      requestResponseMap.put(list, notFound);
 
-      requestResponseMap.put(createSecurityGroupWithPrefixOnGroup, securityGroupCreated);
+      requestResponseMap.put(createWithPrefixOnGroup, securityGroupCreated);
 
-      requestResponseMap.put(createSecurityGroupRuleForDefaultPort22, securityGroupRuleCreated);
+      requestResponseMap.put(createRuleForDefaultPort22, securityGroupRuleCreated);
 
       requestResponseMap.put(getSecurityGroup, securityGroupWithPort22);
 
-      requestResponseMap.put(createKeyPair, keyPairWithPrivateKey);
+      requestResponseMap.put(create, keyPairWithPrivateKey);
 
       requestResponseMap.put(serverDetail, serverDetailResponse);
 
@@ -266,11 +266,11 @@
    public void testCreateNodeWhileUserSpecifiesKeyPair() throws Exception {
       Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
             .putAll(defaultTemplateTryStack);
-      requestResponseMap.put(listSecurityGroups, notFound);
+      requestResponseMap.put(list, notFound);
 
-      requestResponseMap.put(createSecurityGroupWithPrefixOnGroup, securityGroupCreated);
+      requestResponseMap.put(createWithPrefixOnGroup, securityGroupCreated);
 
-      requestResponseMap.put(createSecurityGroupRuleForDefaultPort22, securityGroupRuleCreated);
+      requestResponseMap.put(createRuleForDefaultPort22, securityGroupRuleCreated);
 
       requestResponseMap.put(getSecurityGroup, securityGroupWithPort22);
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java
index ebd632b..97f763d 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/functions/AllocateAndAddFloatingIpToNodeExpectTest.java
@@ -57,7 +57,7 @@
             host).name("Server 71592").status(Status.RUNNING).privateAddresses(ImmutableSet.of("10.4.27.237"))
             .credentials(LoginCredentials.builder().password("foo").build()).build();
 
-   HttpRequest allocateFloatingIP = HttpRequest.builder().method("POST").endpoint(
+   HttpRequest createFloatingIP = HttpRequest.builder().method("POST").endpoint(
             URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")).headers(
             ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                      authToken).build()).payload(payloadFromStringWithContentType("{}", "application/json")).build();
@@ -65,7 +65,7 @@
    HttpResponse addFloatingIPResponse = HttpResponse.builder().statusCode(200).build();
 
    public void testAllocateWhenAllocationReturnsIpIsAddedToServerAndUpdatesNodeMetadataButSavesCredentials() throws Exception {
-      HttpResponse allocateFloatingIPResponse = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse createFloatingIPResponse = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/floatingip_details.json")).build();
 
       HttpRequest addFloatingIPRequest = addFloatingIPForAddress("10.0.0.3");
@@ -73,7 +73,7 @@
       AllocateAndAddFloatingIpToNode fn = requestsSendResponses(
                ImmutableMap.<HttpRequest, HttpResponse> builder().put(keystoneAuthWithUsernameAndPasswordAndTenantName,
                         responseWithKeystoneAccess).put(extensionsOfNovaRequest, extensionsOfNovaResponse).put(
-                        allocateFloatingIP, allocateFloatingIPResponse)
+                        createFloatingIP, createFloatingIPResponse)
                         .put(addFloatingIPRequest, addFloatingIPResponse).build()).getContext().utils().injector()
                .getInstance(AllocateAndAddFloatingIpToNode.class);
 
@@ -98,20 +98,20 @@
    }
 
    public void testAllocateWhenAllocationFailsLookupUnusedIpAddToServerAndUpdatesNodeMetadata() throws Exception {
-      HttpResponse allocateFloatingIPResponse = HttpResponse
+      HttpResponse createFloatingIPResponse = HttpResponse
                .builder()
                .statusCode(400)
                .payload(
                         payloadFromStringWithContentType(
-                                 "{\"badRequest\": {\"message\": \"AddressLimitExceeded: Address quota exceeded. You cannot allocate any more addresses\", \"code\": 400}}",
+                                 "{\"badRequest\": {\"message\": \"AddressLimitExceeded: Address quota exceeded. You cannot create any more addresses\", \"code\": 400}}",
                                  "application/json")).build();
 
-      HttpRequest listFloatingIPs = HttpRequest.builder().method("GET").endpoint(
+      HttpRequest list = HttpRequest.builder().method("GET").endpoint(
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")).headers(
                ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                         authToken).build()).build();
 
-      HttpResponse listFloatingIPsResponseForUnassigned = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse listResponseForUnassigned = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/floatingip_list.json")).build();
 
       HttpRequest addFloatingIPRequest = addFloatingIPForAddress("10.0.0.5");
@@ -119,9 +119,9 @@
       AllocateAndAddFloatingIpToNode fn = requestsSendResponses(
                ImmutableMap.<HttpRequest, HttpResponse> builder().put(keystoneAuthWithUsernameAndPasswordAndTenantName,
                         responseWithKeystoneAccess).put(extensionsOfNovaRequest, extensionsOfNovaResponse).put(
-                        allocateFloatingIP, allocateFloatingIPResponse)
-                        .put(addFloatingIPRequest, addFloatingIPResponse).put(listFloatingIPs,
-                                 listFloatingIPsResponseForUnassigned).build()).getContext().utils().injector()
+                        createFloatingIP, createFloatingIPResponse)
+                        .put(addFloatingIPRequest, addFloatingIPResponse).put(list,
+                                 listResponseForUnassigned).build()).getContext().utils().injector()
                .getInstance(AllocateAndAddFloatingIpToNode.class);
 
       AtomicReference<NodeMetadata> nodeRef = new AtomicReference<NodeMetadata>(node);
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPairTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPairTest.java
index c2de758..b7552a3 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPairTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/loaders/CreateUniqueKeyPairTest.java
@@ -56,7 +56,7 @@
       
       expect(api.getKeyPairExtensionForZone("zone")).andReturn(optKeyApi).atLeastOnce();
 
-      expect(keyApi.createKeyPair("group-1")).andReturn(pair);
+      expect(keyApi.create("group-1")).andReturn(pair);
 
       replay(api, keyApi);
 
@@ -88,9 +88,9 @@
       expect(api.getKeyPairExtensionForZone("zone")).andReturn((Optional) Optional.of(keyApi)).atLeastOnce();
 
       expect(uniqueIdSupplier.get()).andReturn("1");
-      expect(keyApi.createKeyPair("group-1")).andThrow(new IllegalStateException());
+      expect(keyApi.create("group-1")).andThrow(new IllegalStateException());
       expect(uniqueIdSupplier.get()).andReturn("2");
-      expect(keyApi.createKeyPair("group-2")).andReturn(pair);
+      expect(keyApi.create("group-2")).andReturn(pair);
 
       replay(api, keyApi, uniqueIdSupplier);
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstanceTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstanceTest.java
index 291d89e..f4afb77 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstanceTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/loaders/LoadFloatingIpsForInstanceTest.java
@@ -34,6 +34,7 @@
 import org.testng.annotations.Test;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -49,7 +50,8 @@
       FloatingIP testIp = FloatingIP.builder().id("1").ip("1.1.1.1").fixedIp("10.1.1.1").instanceId("i-blah").build();
 
       expect(api.getFloatingIPExtensionForZone("Zone")).andReturn((Optional) Optional.of(ipApi)).atLeastOnce();
-      expect(ipApi.listFloatingIPs()).andReturn((Set) ImmutableSet.<FloatingIP>of(testIp)).atLeastOnce();
+      expect(ipApi.list()).andReturn((FluentIterable) FluentIterable.from(ImmutableSet.<FloatingIP> of(testIp)))
+               .atLeastOnce();
 
       replay(api);
       replay(ipApi);
@@ -69,7 +71,8 @@
 
       expect(api.getFloatingIPExtensionForZone("Zone")).andReturn((Optional) Optional.of(ipApi)).atLeastOnce();
 
-      expect(ipApi.listFloatingIPs()).andReturn((Set) ImmutableSet.<FloatingIP>of()).atLeastOnce();
+      expect(ipApi.list()).andReturn((FluentIterable) FluentIterable.from(ImmutableSet.<FloatingIP> of()))
+      .atLeastOnce();
 
       replay(api);
       replay(ipApi);
@@ -90,9 +93,8 @@
 
       expect(api.getFloatingIPExtensionForZone("Zone")).andReturn((Optional) Optional.of(ipApi)).atLeastOnce();
 
-      expect(ipApi.listFloatingIPs()).andReturn(
-            (Set) ImmutableSet.<FloatingIP>of(FloatingIP.builder().id("1").ip("1.1.1.1").build()))
-            .atLeastOnce();
+      expect(ipApi.list()).andReturn((FluentIterable) FluentIterable.from(ImmutableSet.<FloatingIP> of(FloatingIP.builder().id("1").ip("1.1.1.1").build())))
+      .atLeastOnce();
 
       replay(api);
       replay(ipApi);
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/predicates/GetImageWhenImageInZoneHasActiveStatusPredicateWithResultExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/predicates/GetImageWhenImageInZoneHasActiveStatusPredicateWithResultExpectTest.java
index 8be5dd2..f9da95e 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/predicates/GetImageWhenImageInZoneHasActiveStatusPredicateWithResultExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/compute/predicates/GetImageWhenImageInZoneHasActiveStatusPredicateWithResultExpectTest.java
@@ -45,12 +45,12 @@
 public class GetImageWhenImageInZoneHasActiveStatusPredicateWithResultExpectTest extends
          BaseNovaComputeServiceContextExpectTest<Injector> {
 
-   private final HttpResponse listImagesDetailImageExtensionResponse = HttpResponse.builder().statusCode(200)
+   private final HttpResponse listDetailImageExtensionResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/image_list_detail_imageextension.json")).build();
 
    private Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
             .put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess)
-            .put(listImagesDetail, listImagesDetailImageExtensionResponse).build();
+            .put(listDetail, listDetailImageExtensionResponse).build();
 
    public void testReturnsFalseOnImageStatusSavingAndTrueOnActive() {
       Injector injector = requestsSendResponses(requestResponseMap);
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApiExpectTest.java
index 6980ab1..e2906f7 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApiExpectTest.java
@@ -47,298 +47,298 @@
 
    public void testSuspend() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.suspendServer("1"));
+      assertTrue(api.suspend("1"));
    }
 
    public void testSuspendFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.suspendServer("1"));
+      assertFalse(api.suspend("1"));
    }
 
    @Test(expectedExceptions = AuthorizationException.class)
    public void testSuspendFailsNotAuthorized() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "suspend").build(),
             HttpResponse.builder().statusCode(403).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      api.suspendServer("1");
+      api.suspend("1");
    }
    
    public void testResume() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.resumeServer("1"));
+      assertTrue(api.resume("1"));
    }
 
    public void testResumeFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.resumeServer("1"));
+      assertFalse(api.resume("1"));
    }
 
    @Test(expectedExceptions = AuthorizationException.class)
    public void testResumeFailsNotAuthorized() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "resume").build(),
             HttpResponse.builder().statusCode(403).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      api.resumeServer("1");
+      api.resume("1");
    }
 
    public void testLock() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "lock").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.lockServer("1"));
+      assertTrue(api.lock("1"));
    }
 
    public void testLockFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "lock").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.lockServer("1"));
+      assertFalse(api.lock("1"));
    }
 
    public void testUnlock() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "unlock").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.unlockServer("1"));
+      assertTrue(api.unlock("1"));
    }
 
    public void testUnlockFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "unlock").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.unlockServer("1"));
+      assertFalse(api.unlock("1"));
    }
 
    public void testPause() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "pause").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.pauseServer("1"));
+      assertTrue(api.pause("1"));
    }
 
    public void testPauseFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "pause").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.pauseServer("1"));
+      assertFalse(api.pause("1"));
    }
    
    public void testUnpause() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "unpause").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.unpauseServer("1"));
+      assertTrue(api.unpause("1"));
    }
 
    public void testUnpauseFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "unpause").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.unpauseServer("1"));
+      assertFalse(api.unpause("1"));
    }
    
    public void testMigrateServer() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "migrate").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.migrateServer("1"));
+      assertTrue(api.migrate("1"));
    }
 
 
    public void testMigrateServerFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "migrate").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.migrateServer("1"));
+      assertFalse(api.migrate("1"));
    }
 
    public void testResetNetworkOfServer() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "resetNetwork").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.resetNetworkOfServer("1"));
+      assertTrue(api.resetNetwork("1"));
    }
 
    public void testResetNetworkOfServerFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "resetNetwork").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.resetNetworkOfServer("1"));
+      assertFalse(api.resetNetwork("1"));
    }
    
    public void testInjectNetworkInfoIntoServer() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "injectNetworkInfo").build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.injectNetworkInfoIntoServer("1"));
+      assertTrue(api.injectNetworkInfo("1"));
    }
 
    public void testInjectNetworkInfoIntoServerFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "injectNetworkInfo").build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.injectNetworkInfoIntoServer("1"));
+      assertFalse(api.injectNetworkInfo("1"));
    }
    
    public void testBackupServer() {
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             authenticatedGET().endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action").method("POST")
                   .payload(payloadFromStringWithContentType("{\"createBackup\":{\"backup_type\":\"weekly\",\"rotation\":3,\"name\":\"mybackup\",\"metadata\":{\"some\":\"data or other\"}}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(202).addHeader("Location", "http://172.16.89.149:8774/v2/images/1976b3b3-409a-468d-b16c-a9172c341b46").build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      String imageId = api.createBackupOfServer("1", "mybackup", BackupType.WEEKLY, 3, CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("some", "data or other")));
+      String imageId = api.createBackup("1", "mybackup", BackupType.WEEKLY, 3, CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("some", "data or other")));
       assertEquals(imageId, "1976b3b3-409a-468d-b16c-a9172c341b46");
    }
 
    @Test(expectedExceptions = ResourceNotFoundException.class)
    public void testBackupServerFailNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             authenticatedGET().endpoint(endpoint).method("POST")
                   .payload(payloadFromStringWithContentType("{\"createBackup\":{\"backup_type\":\"weekly\",\"rotation\":3,\"name\":\"mybackup\",\"metadata\":{\"some\":\"data or other\"}}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      api.createBackupOfServer("1", "mybackup", BackupType.WEEKLY, 3, CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("some", "data or other")));
+      api.createBackup("1", "mybackup", BackupType.WEEKLY, 3, CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("some", "data or other")));
    }
 
    public void testLiveMigrateServer() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "GONNAOVERWRITE")
                   .payload(payloadFromStringWithContentType("{\"os-migrateLive\":{\"host\":\"bighost\",\"block_migration\":true,\"disk_over_commit\":false}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(202).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.liveMigrateServer("1", "bighost", true, false));
+      assertTrue(api.liveMigrate("1", "bighost", true, false));
    }
 
    public void testLiveMigrateServerFailsNotFound() {
       URI endpoint = URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/1/action");
-      AdminActionsApi api = requestsSendResponses(
+      ServerAdminApi api = requestsSendResponses(
             keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             standardActionRequestBuilderVoidResponse(endpoint, "GONNAOVERWRITE")
                   .payload(payloadFromStringWithContentType("{\"os-migrateLive\":{\"host\":\"bighost\",\"block_migration\":true,\"disk_over_commit\":false}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(404).build()
-      ).getAdminActionsExtensionForZone("az-1.region-a.geo-1").get();
+      ).getServerAdminExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.liveMigrateServer("1", "bighost", true, false));
+      assertFalse(api.liveMigrate("1", "bighost", true, false));
    }
    
    protected HttpRequest.Builder<?> standardActionRequestBuilderVoidResponse(URI endpoint, String actionName) {
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApiLiveTest.java
index ae1bc4a..40312f4 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/AdminActionsApiLiveTest.java
@@ -32,9 +32,10 @@
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
 import org.jclouds.openstack.nova.v2_0.options.CreateBackupOfServerOptions;
 import org.jclouds.openstack.v2_0.features.ExtensionApi;
-import org.testng.annotations.AfterGroups;
+import org.testng.SkipException;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Optional;
@@ -45,7 +46,7 @@
  * Tests behavior of HostAdministrationApi
  * 
  * TODO test migration methods
- *
+ * 
  * @author Adam Lowe
  */
 @Test(groups = "live", testName = "AdminActionsApiLiveTest", singleThreaded = true)
@@ -53,13 +54,13 @@
    private ImageApi imageApi;
    private ServerApi serverApi;
    private ExtensionApi extensionApi;
-   private Optional<? extends AdminActionsApi> apiOption;
+   private Optional<? extends ServerAdminApi> apiOption;
    private String zone;
 
    private String testServerId;
    private String backupImageId;
 
-   @BeforeGroups(groups = {"integration", "live"})
+   @BeforeClass(groups = {"integration", "live"})
    @Override
    public void setupContext() {
       super.setupContext();
@@ -67,125 +68,130 @@
       serverApi = novaContext.getApi().getServerApiForZone(zone);
       extensionApi = novaContext.getApi().getExtensionApiForZone(zone);
       imageApi = novaContext.getApi().getImageApiForZone(zone);
-      apiOption = novaContext.getApi().getAdminActionsExtensionForZone(zone);
+      apiOption = novaContext.getApi().getServerAdminExtensionForZone(zone);
       if (apiOption.isPresent()) {
          testServerId = createServerInZone(zone).getId();
       }
    }
 
-   @AfterGroups(groups = "live", alwaysRun = true)
+   @AfterClass(groups = { "integration", "live" })
    @Override
-   protected void tearDown() {
+   protected void tearDownContext() {
       if (apiOption.isPresent()) {
          if (testServerId != null) {
-            assertTrue(novaContext.getApi().getServerApiForZone(zone).deleteServer(testServerId));
+            assertTrue(novaContext.getApi().getServerApiForZone(zone).delete(testServerId));
          }
          if (backupImageId != null) {
-            imageApi.deleteImage(backupImageId);
+            imageApi.delete(backupImageId);
          }
       }
-      super.tearDown();
+      super.tearDownContext();
+   }
+
+   protected void skipOnAdminExtensionAbsent() {
+      if (!apiOption.isPresent()) {
+         throw new SkipException("Test depends on ServerAdminApi extension");
+      }
    }
 
    @AfterMethod(alwaysRun = true)
    public void ensureServerIsActiveAgain() {
-      blockUntilServerInState(testServerId, serverApi, Status.ACTIVE);
-   }
-   
-   public void testSuspendAndResume() {
-      if (apiOption.isPresent()) {
-         AdminActionsApi api = apiOption.get();
-
-         // Suspend-resume
-         try {
-            api.resumeServer(testServerId);
-            fail("Resumed an active server!");
-         } catch (HttpResponseException e) {
-         }
-         assertTrue(api.suspendServer(testServerId));
-         blockUntilServerInState(testServerId, serverApi, Status.SUSPENDED);
-         try {
-            api.suspendServer(testServerId);
-            fail("Suspended an already suspended server!");
-         } catch (HttpResponseException e) {
-         }
-         assertTrue(api.resumeServer(testServerId));
+      if (apiOption.isPresent())
          blockUntilServerInState(testServerId, serverApi, Status.ACTIVE);
-         try {
-            api.resumeServer(testServerId);
-            fail("Resumed an already resumed server!");
-         } catch (HttpResponseException e) {
-         }
+   }
+
+   public void testSuspendAndResume() {
+      skipOnAdminExtensionAbsent();
+      ServerAdminApi api = apiOption.get();
+
+      // Suspend-resume
+      try {
+         api.resume(testServerId);
+         fail("Resumed an active server!");
+      } catch (HttpResponseException e) {
       }
+      assertTrue(api.suspend(testServerId));
+      blockUntilServerInState(testServerId, serverApi, Status.SUSPENDED);
+      try {
+         api.suspend(testServerId);
+         fail("Suspended an already suspended server!");
+      } catch (HttpResponseException e) {
+      }
+      assertTrue(api.resume(testServerId));
+      blockUntilServerInState(testServerId, serverApi, Status.ACTIVE);
+      try {
+         api.resume(testServerId);
+         fail("Resumed an already resumed server!");
+      } catch (HttpResponseException e) {
+      }
+
    }
 
    public void testLockAndUnlock() {
-      if (apiOption.isPresent()) {
-         AdminActionsApi api = apiOption.get();
+      skipOnAdminExtensionAbsent();
+      ServerAdminApi api = apiOption.get();
 
-         // TODO should we be able to double-lock (as it were)
-         assertTrue(api.unlockServer(testServerId));
-         assertTrue(api.unlockServer(testServerId));
-         assertTrue(api.lockServer(testServerId));
-         assertTrue(api.lockServer(testServerId));
-         assertTrue(api.unlockServer(testServerId));
-         assertTrue(api.unlockServer(testServerId));
-      }
+      // TODO should we be able to double-lock (as it were)
+      assertTrue(api.unlock(testServerId));
+      assertTrue(api.unlock(testServerId));
+      assertTrue(api.lock(testServerId));
+      assertTrue(api.lock(testServerId));
+      assertTrue(api.unlock(testServerId));
+      assertTrue(api.unlock(testServerId));
+
    }
 
    public void testResetNetworkAndInjectNetworkInfo() {
-      if (apiOption.isPresent()) {
-         AdminActionsApi api = apiOption.get();
-         assertTrue(api.resetNetworkOfServer(testServerId));
-         assertTrue(api.injectNetworkInfoIntoServer(testServerId));
-      }
+      skipOnAdminExtensionAbsent();
+      ServerAdminApi api = apiOption.get();
+      assertTrue(api.resetNetwork(testServerId));
+      assertTrue(api.injectNetworkInfo(testServerId));
    }
 
    @Test
    public void testPauseAndUnpause() {
-      if (apiOption.isPresent()) {
-         AdminActionsApi api = apiOption.get();
+      skipOnAdminExtensionAbsent();
+      ServerAdminApi api = apiOption.get();
 
-         // Unlock and lock (double-checking error contitions too)
-         try {
-            api.unpauseServer(testServerId);
-            fail("Unpaused active server!");
-         } catch (HttpResponseException e) {
-         }
-         assertTrue(api.pauseServer(testServerId));
-         blockUntilServerInState(testServerId, serverApi, Status.PAUSED);
-         try {
-            api.pauseServer(testServerId);
-            fail("paused a paused server!");
-         } catch (HttpResponseException e) {
-         }
-         assertTrue(api.unpauseServer(testServerId));
-         blockUntilServerInState(testServerId, serverApi, Status.ACTIVE);
-         try {
-            api.unpauseServer(testServerId);
-            fail("Unpaused a server we just unpaused!");
-         } catch (HttpResponseException e) {
-         }
+      // Unlock and lock (double-checking error contitions too)
+      try {
+         api.unpause(testServerId);
+         fail("Unpaused active server!");
+      } catch (HttpResponseException e) {
       }
+      assertTrue(api.pause(testServerId));
+      blockUntilServerInState(testServerId, serverApi, Status.PAUSED);
+      try {
+         api.pause(testServerId);
+         fail("paused a paused server!");
+      } catch (HttpResponseException e) {
+      }
+      assertTrue(api.unpause(testServerId));
+      blockUntilServerInState(testServerId, serverApi, Status.ACTIVE);
+      try {
+         api.unpause(testServerId);
+         fail("Unpaused a server we just unpaused!");
+      } catch (HttpResponseException e) {
+      }
+
    }
 
    @Test
    public void testCreateBackupOfServer() throws InterruptedException {
-      if (apiOption.isPresent()) {
-         backupImageId = apiOption.get().createBackupOfServer(testServerId, "jclouds-test-backup", BackupType.DAILY, 0,
+      skipOnAdminExtensionAbsent();
+      backupImageId = apiOption.get().createBackup(testServerId, "jclouds-test-backup", BackupType.DAILY, 0,
                CreateBackupOfServerOptions.Builder.metadata(ImmutableMap.of("test", "metadata")));
 
-         assertNotNull(backupImageId);
-         
-         // If we don't have extended task status, we'll have to wait here!
-         if (extensionApi.getExtensionByAlias("OS-EXT-STS") == null) {
-            Thread.sleep(30000);
-         }
-         
-         blockUntilServerInState(testServerId, serverApi, Status.ACTIVE);
-         
-         Image backupImage = imageApi.getImage(backupImageId);
-         assertEquals(backupImage.getId(), backupImageId);
+      assertNotNull(backupImageId);
+
+      // If we don't have extended task status, we'll have to wait here!
+      if (extensionApi.get("OS-EXT-STS") == null) {
+         Thread.sleep(30000);
       }
-   }   
+
+      blockUntilServerInState(testServerId, serverApi, Status.ACTIVE);
+
+      Image backupImage = imageApi.get(backupImageId);
+      assertEquals(backupImage.getId(), backupImageId);
+   }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApiExpectTest.java
index f483ece..3832a39 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApiExpectTest.java
@@ -50,7 +50,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type_extra_specs.json")).build()
       ).getFlavorExtraSpecsExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertEquals(api.getAllExtraSpecs("9"), ImmutableMap.of("test", "value1"));
+      assertEquals(api.getMetadata("9"), ImmutableMap.of("test", "value1"));
    }
 
    public void testGetAllExtraSpecsFailNotFound() {
@@ -62,7 +62,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getFlavorExtraSpecsExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.getAllExtraSpecs("9").isEmpty());
+      assertTrue(api.getMetadata("9").isEmpty());
    }
 
    public void testSetAllExtraSpecs() {
@@ -76,7 +76,7 @@
             HttpResponse.builder().statusCode(200).build()
       ).getFlavorExtraSpecsExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.setAllExtraSpecs("9", ImmutableMap.of("test1", "somevalue")));
+      assertTrue(api.updateMetadata("9", ImmutableMap.of("test1", "somevalue")));
    }
 
    public void testSetExtraSpec() {
@@ -90,7 +90,7 @@
             HttpResponse.builder().statusCode(200).build()
       ).getFlavorExtraSpecsExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.setExtraSpec("5", "test1", "somevalue"));
+      assertTrue(api.updateMetadataEntry("5", "test1", "somevalue"));
    }
 
    public void testGetExtraSpec() {
@@ -102,7 +102,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromStringWithContentType("{\"test1\":\"another value\"}", MediaType.APPLICATION_JSON)).build()
       ).getFlavorExtraSpecsExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertEquals(api.getExtraSpec("5", "test1"), "another value");
+      assertEquals(api.getMetadataKey("5", "test1"), "another value");
    }
 
    public void testGetExtraSpecFailNotFound() {
@@ -114,7 +114,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getFlavorExtraSpecsExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertNull(api.getExtraSpec("5", "test1"));
+      assertNull(api.getMetadataKey("5", "test1"));
    }
 
    public void testDeleteExtraSpec() {
@@ -126,7 +126,7 @@
             HttpResponse.builder().statusCode(200).build()
       ).getFlavorExtraSpecsExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.deleteExtraSpec("5", "test1"));
+      assertTrue(api.deleteMetadataKey("5", "test1"));
    }
 
    public void testDeleteExtraSpecFailNotFound() {
@@ -138,7 +138,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getFlavorExtraSpecsExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.deleteExtraSpec("5", "test1"));
+      assertFalse(api.deleteMetadataKey("5", "test1"));
    }
 
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApiLiveTest.java
index a666aaf..0b24f84 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FlavorExtraSpecsApiLiveTest.java
@@ -27,8 +27,8 @@
 import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
 import org.jclouds.openstack.v2_0.domain.Resource;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Optional;
@@ -50,7 +50,7 @@
    private Resource testFlavor;
    private Map<String, String> testSpecs = ImmutableMap.of("jclouds-test", "some data", "jclouds-test2", "more data!");
 
-   @BeforeGroups(groups = { "integration", "live" })
+   @BeforeClass(groups = {"integration", "live"})
    @Override
    public void setupContext() {
       super.setupContext();
@@ -59,29 +59,29 @@
       apiOption = novaContext.getApi().getFlavorExtraSpecsExtensionForZone(zone);
    }
 
-   @AfterGroups(groups = "live")
+   @AfterClass(groups = { "integration", "live" })
    @Override
-   public void tearDown() {
+   protected void tearDownContext() {
       if (apiOption.isPresent() && testFlavor != null) {
          for(String key : testSpecs.keySet()) {
-            assertTrue(apiOption.get().deleteExtraSpec(testFlavor.getId(), key));
+            assertTrue(apiOption.get().deleteMetadataKey(testFlavor.getId(), key));
          }
       }
-      super.tearDown();
+      super.tearDownContext();
    }
 
    public void testCreateExtraSpecs() {
       if (apiOption.isPresent()) {
          FlavorExtraSpecsApi api = apiOption.get();
-         testFlavor = Iterables.getLast(flavorApi.listFlavors());
-         Map<String, String> before = api.getAllExtraSpecs(testFlavor.getId());
+         testFlavor = Iterables.getLast(flavorApi.list().concat());
+         Map<String, String> before = api.getMetadata(testFlavor.getId());
          assertNotNull(before);
          Map<String, String> specs = Maps.newHashMap(before);
          specs.putAll(testSpecs);
-         assertTrue(api.setAllExtraSpecs(testFlavor.getId(), specs));
-         assertEquals(api.getAllExtraSpecs(testFlavor.getId()), specs);
+         assertTrue(api.updateMetadata(testFlavor.getId(), specs));
+         assertEquals(api.getMetadata(testFlavor.getId()), specs);
          for (Map.Entry<String, String> entry : specs.entrySet()) {
-            assertEquals(api.getExtraSpec(testFlavor.getId(), entry.getKey()), entry.getValue());
+            assertEquals(api.getMetadataKey(testFlavor.getId(), entry.getKey()), entry.getValue());
          }
       }
    }
@@ -91,13 +91,13 @@
       if (apiOption.isPresent()) {
          FlavorExtraSpecsApi api = apiOption.get();
          for (String key : testSpecs.keySet()) {
-            assertTrue(api.getAllExtraSpecs(testFlavor.getId()).containsKey(key));
+            assertTrue(api.getMetadata(testFlavor.getId()).containsKey(key));
          }
-         for (Resource flavor : flavorApi.listFlavors()) {
-            Map<String, String> specs = api.getAllExtraSpecs(flavor.getId());
+         for (Resource flavor : flavorApi.list().concat()) {
+            Map<String, String> specs = api.getMetadata(flavor.getId());
             assertNotNull(specs);
             for (Map.Entry<String, String> entry : specs.entrySet()) {
-               assertEquals(api.getExtraSpec(flavor.getId(), entry.getKey()), entry.getValue());
+               assertEquals(api.getMetadataKey(flavor.getId(), entry.getKey()), entry.getValue());
             }
          }
       }
@@ -108,16 +108,16 @@
       if (apiOption.isPresent()) {
          FlavorExtraSpecsApi api = apiOption.get();
          for (String key : testSpecs.keySet()) {
-            assertTrue(api.setExtraSpec(testFlavor.getId(), key, "new value"));
+            assertTrue(api.updateMetadataEntry(testFlavor.getId(), key, "new value"));
          }
          for (String key : testSpecs.keySet()) {
-            assertEquals(api.getExtraSpec(testFlavor.getId(), key), "new value");
+            assertEquals(api.getMetadataKey(testFlavor.getId(), key), "new value");
          }
-         for (Resource flavor : flavorApi.listFlavors()) {
-            Map<String, String> specs = api.getAllExtraSpecs(flavor.getId());
+         for (Resource flavor : flavorApi.list().concat()) {
+            Map<String, String> specs = api.getMetadata(flavor.getId());
             assertNotNull(specs);
             for (Map.Entry<String, String> entry : specs.entrySet()) {
-               assertEquals(api.getExtraSpec(flavor.getId(), entry.getKey()), entry.getValue());
+               assertEquals(api.getMetadataKey(flavor.getId(), entry.getKey()), entry.getValue());
             }
          }
       }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApiExpectTest.java
index af71ea1..141408e 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApiExpectTest.java
@@ -63,77 +63,77 @@
    }
 
    public void testListFloatingIPsWhenResponseIs2xx() throws Exception {
-      HttpRequest listFloatingIPs = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listFloatingIPsResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/floatingip_list.json")).build();
 
       NovaApi apiWhenFloatingIPsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listFloatingIPs, listFloatingIPsResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list, listResponse);
 
       assertEquals(apiWhenFloatingIPsExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().listFloatingIPs()
+      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().list()
             .toString(), new ParseFloatingIPListTest().expected().toString());
    }
 
    public void testListFloatingIPsWhenResponseIs404() throws Exception {
-      HttpRequest listFloatingIPs = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listFloatingIPsResponse = HttpResponse.builder().statusCode(404).build();
+      HttpResponse listResponse = HttpResponse.builder().statusCode(404).build();
 
       NovaApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listFloatingIPs, listFloatingIPsResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list, listResponse);
 
-      assertTrue(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().listFloatingIPs().isEmpty());
+      assertTrue(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().list().isEmpty());
    }
 
    public void testGetFloatingIPWhenResponseIs2xx() throws Exception {
-      HttpRequest getFloatingIP = HttpRequest
+      HttpRequest get = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips/1")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse getFloatingIPResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse getResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/floatingip_details.json")).build();
 
       NovaApi apiWhenFloatingIPsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, getFloatingIP, getFloatingIPResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, get, getResponse);
 
-      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().getFloatingIP("1")
+      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().get("1")
             .toString(), new ParseFloatingIPTest().expected().toString());
    }
 
    public void testGetFloatingIPWhenResponseIs404() throws Exception {
-      HttpRequest getFloatingIP = HttpRequest
+      HttpRequest get = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips/1")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse getFloatingIPResponse = HttpResponse.builder().statusCode(404).build();
+      HttpResponse getResponse = HttpResponse.builder().statusCode(404).build();
 
       NovaApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, getFloatingIP, getFloatingIPResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, get, getResponse);
 
-      assertNull(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().getFloatingIP("1"));
+      assertNull(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().get("1"));
    }
 
    public void testAllocateWhenResponseIs2xx() throws Exception {
-      HttpRequest allocateFloatingIP = HttpRequest
+      HttpRequest createFloatingIP = HttpRequest
             .builder()
             .method("POST")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
@@ -141,20 +141,20 @@
             .addHeader("X-Auth-Token", authToken)
             .payload(payloadFromStringWithContentType("{}", "application/json")).build();
 
-      HttpResponse allocateFloatingIPResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse createFloatingIPResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/floatingip_details.json")).build();
 
       NovaApi apiWhenFloatingIPsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, allocateFloatingIP,
-            allocateFloatingIPResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createFloatingIP,
+            createFloatingIPResponse);
 
-      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().allocate().toString(),
+      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().create().toString(),
             new ParseFloatingIPTest().expected().toString());
 
    }
 
    public void testAllocateWhenResponseIs404() throws Exception {
-      HttpRequest allocateFloatingIP = HttpRequest
+      HttpRequest createFloatingIP = HttpRequest
             .builder()
             .method("POST")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
@@ -162,13 +162,13 @@
             .addHeader("X-Auth-Token", authToken)
             .payload(payloadFromStringWithContentType("{}", "application/json")).build();
 
-      HttpResponse allocateFloatingIPResponse = HttpResponse.builder().statusCode(404).build();
+      HttpResponse createFloatingIPResponse = HttpResponse.builder().statusCode(404).build();
 
       NovaApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, allocateFloatingIP,
-            allocateFloatingIPResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createFloatingIP,
+            createFloatingIPResponse);
 
-      assertNull(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().allocate());
+      assertNull(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().create());
    }
 
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApiLiveTest.java
index a35aaab..164be4f 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPApiLiveTest.java
@@ -52,11 +52,11 @@
          if (!apiOption.isPresent())
             continue;
          FloatingIPApi api = apiOption.get();
-         Set<? extends FloatingIP> response = api.listFloatingIPs();
+         Set<? extends FloatingIP> response = api.list().toImmutableSet();
          assert null != response;
          assertTrue(response.size() >= 0);
          for (FloatingIP ip : response) {
-            FloatingIP newDetails = api.getFloatingIP(ip.getId());
+            FloatingIP newDetails = api.get(ip.getId());
 
             assertEquals(newDetails.getId(), ip.getId());
             assertEquals(newDetails.getIp(), ip.getIp());
@@ -68,16 +68,16 @@
    }
 
    @Test
-   public void testAllocateAndDeallocateFloatingIPs() throws Exception {
+   public void testAllocateAndDecreateFloatingIPs() throws Exception {
       for (String zoneId : novaContext.getApi().getConfiguredZones()) {
          Optional<? extends FloatingIPApi> apiOption = novaContext.getApi().getFloatingIPExtensionForZone(zoneId);
          if (!apiOption.isPresent())
             continue;
          FloatingIPApi api = apiOption.get();
-         FloatingIP floatingIP = api.allocate();
+         FloatingIP floatingIP = api.create();
          assertNotNull(floatingIP);
 
-         Set<? extends FloatingIP> response = api.listFloatingIPs();
+         Set<? extends FloatingIP> response = api.list().toImmutableSet();
          boolean ipInSet = false;
          for (FloatingIP ip : response) {
             if (ip.getId().equals(floatingIP.getId()))
@@ -85,9 +85,9 @@
          }
          assertTrue(ipInSet);
 
-         api.deallocate(floatingIP.getId());
+         api.delete(floatingIP.getId());
 
-         response = api.listFloatingIPs();
+         response = api.list().toImmutableSet();
          ipInSet = false;
          for (FloatingIP ip : response) {
             if (ip.getId().equals(floatingIP.getId())) {
@@ -107,14 +107,14 @@
          FloatingIPApi api = apiOption.get();
          ServerApi serverApi = novaContext.getApi().getServerApiForZone(zoneId);
          Server server = createServerInZone(zoneId);
-         FloatingIP floatingIP = api.allocate();
+         FloatingIP floatingIP = api.create();
          assertNotNull(floatingIP);
          try {
-            api.addFloatingIPToServer(floatingIP.getIp(), server.getId());
+            api.addToServer(floatingIP.getIp(), server.getId());
             assertEventually(new ServerHasFloatingIP(serverApi, server.getId(), floatingIP.getIp()));
          } finally {
-            api.removeFloatingIPFromServer(floatingIP.getIp(), server.getId());
-            serverApi.deleteServer(server.getId());
+            api.removeFromServer(floatingIP.getIp(), server.getId());
+            serverApi.delete(server.getId());
          }
       }
    }
@@ -155,7 +155,7 @@
 
       public void run() {
          try {
-            Server server = api.getServer(serverId);
+            Server server = api.get(serverId);
             boolean ipInServerAddresses = false;
             Multimap<String, Address> addresses = server.getAddresses();
             for (Address address : addresses.values()) {
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPAsyncApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPAsyncApiExpectTest.java
index 32f1506..42b81d3 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPAsyncApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/FloatingIPAsyncApiExpectTest.java
@@ -64,78 +64,78 @@
    }
 
    public void testListFloatingIPsWhenResponseIs2xx() throws Exception {
-      HttpRequest listFloatingIPs = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listFloatingIPsResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/floatingip_list.json")).build();
 
       NovaAsyncApi apiWhenFloatingIPsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listFloatingIPs, listFloatingIPsResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list, listResponse);
 
       assertEquals(apiWhenFloatingIPsExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().listFloatingIPs().get()
+      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().list().get()
             .toString(), new ParseFloatingIPListTest().expected().toString());
    }
 
    public void testListFloatingIPsWhenResponseIs404() throws Exception {
-      HttpRequest listFloatingIPs = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listFloatingIPsResponse = HttpResponse.builder().statusCode(404).build();
+      HttpResponse listResponse = HttpResponse.builder().statusCode(404).build();
 
       NovaAsyncApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listFloatingIPs, listFloatingIPsResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list, listResponse);
 
-      assertTrue(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().listFloatingIPs().get()
+      assertTrue(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().list().get()
             .isEmpty());
    }
 
    public void testGetFloatingIPWhenResponseIs2xx() throws Exception {
-      HttpRequest getFloatingIP = HttpRequest
+      HttpRequest get = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips/1")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse getFloatingIPResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse getResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/floatingip_details.json")).build();
 
       NovaAsyncApi apiWhenFloatingIPsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, getFloatingIP, getFloatingIPResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, get, getResponse);
 
-      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().getFloatingIP("1").get()
+      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().get("1").get()
             .toString(), new ParseFloatingIPTest().expected().toString());
    }
 
    public void testGetFloatingIPWhenResponseIs404() throws Exception {
-      HttpRequest getFloatingIP = HttpRequest
+      HttpRequest get = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips/1")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse getFloatingIPResponse = HttpResponse.builder().statusCode(404).build();
+      HttpResponse getResponse = HttpResponse.builder().statusCode(404).build();
 
       NovaAsyncApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, getFloatingIP, getFloatingIPResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, get, getResponse);
 
-      assertNull(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().getFloatingIP("1").get());
+      assertNull(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().get("1").get());
    }
 
    public void testAllocateWhenResponseIs2xx() throws Exception {
-      HttpRequest allocateFloatingIP = HttpRequest
+      HttpRequest createFloatingIP = HttpRequest
             .builder()
             .method("POST")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
@@ -143,20 +143,20 @@
             .addHeader("X-Auth-Token", authToken)
             .payload(payloadFromStringWithContentType("{}", "application/json")).build();
 
-      HttpResponse allocateFloatingIPResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse createFloatingIPResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/floatingip_details.json")).build();
 
       NovaAsyncApi apiWhenFloatingIPsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, allocateFloatingIP,
-            allocateFloatingIPResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createFloatingIP,
+            createFloatingIPResponse);
 
-      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().allocate().get()
+      assertEquals(apiWhenFloatingIPsExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().create().get()
             .toString(), new ParseFloatingIPTest().expected().toString());
 
    }
 
    public void testAllocateWhenResponseIs404() throws Exception {
-      HttpRequest allocateFloatingIP = HttpRequest
+      HttpRequest createFloatingIP = HttpRequest
             .builder()
             .method("POST")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-floating-ips")
@@ -164,13 +164,13 @@
             .addHeader("X-Auth-Token", authToken)
             .payload(payloadFromStringWithContentType("{}", "application/json")).build();
 
-      HttpResponse allocateFloatingIPResponse = HttpResponse.builder().statusCode(404).build();
+      HttpResponse createFloatingIPResponse = HttpResponse.builder().statusCode(404).build();
 
       NovaAsyncApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, allocateFloatingIP,
-            allocateFloatingIPResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createFloatingIP,
+            createFloatingIPResponse);
 
-      assertNull(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().allocate().get());
+      assertNull(apiWhenNoServersExist.getFloatingIPExtensionForZone("az-1.region-a.geo-1").get().create().get());
    }
 
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApiExpectTest.java
index b824552..f280603 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApiExpectTest.java
@@ -59,7 +59,7 @@
       
       Host expected = Host.builder().name("ubuntu").service("compute").build();
 
-      Set<? extends Host> result = api.listHosts();
+      Set<? extends Host> result = api.list().toImmutableSet();
       Host host = Iterables.getOnlyElement(result);
       assertEquals(host.getName(), "ubuntu");
       assertEquals(host.getService(), "compute");
@@ -84,7 +84,7 @@
             HostResourceUsage.builder().memoryMb(6144).project("f8535069c3fb404cb61c873b1a0b4921").cpu(3).diskGb(80).host("ubuntu").build()
       );
 
-      assertEquals(api.getHostResourceUsage("xyz"), expected);
+      assertEquals(api.listResourceUsage("xyz").toImmutableSet(), expected);
    }
    
    public void testEnableHost() {
@@ -99,7 +99,7 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"status\":\"enabled\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertTrue(api.enableHost("ubuntu"));
+      assertTrue(api.enable("ubuntu"));
    }
 
    @Test(expectedExceptions = ResourceNotFoundException.class)
@@ -114,7 +114,7 @@
                   .endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(404)
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      api.enableHost("ubuntu");
+      api.enable("ubuntu");
    }
 
    public void testEnableHostFailNotEnabled() {
@@ -129,7 +129,7 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"status\":\"disabled\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertFalse(api.enableHost("ubuntu"));
+      assertFalse(api.enable("ubuntu"));
    }
 
    public void testDisableHost() {
@@ -144,7 +144,7 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"status\":\"disabled\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertTrue(api.disableHost("ubuntu"));
+      assertTrue(api.disable("ubuntu"));
    }
 
    public void testStartMaintenance() {
@@ -159,7 +159,7 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"maintenance_mode\":\"on_maintenance\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertTrue(api.startHostMaintenance("ubuntu"));
+      assertTrue(api.startMaintenance("ubuntu"));
    }
 
    public void testStopMaintenance() {
@@ -174,7 +174,7 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"maintenance_mode\":\"off_maintenance\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertTrue(api.stopHostMaintenance("ubuntu"));
+      assertTrue(api.stopMaintenance("ubuntu"));
    }
    
    public void testStartupHost() {
@@ -187,7 +187,7 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"power_action\":\"startup\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertTrue(api.startupHost("ubuntu"));
+      assertTrue(api.startup("ubuntu"));
    }
 
    @Test(expectedExceptions = ResourceNotFoundException.class)
@@ -199,7 +199,7 @@
                        .addHeader("Accept", "application/json")
                        .addHeader("X-Auth-Token", authToken).build(),
             HttpResponse.builder().statusCode(404).build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertTrue(api.startupHost("ubuntu"));
+      assertTrue(api.startup("ubuntu"));
    }
 
    public void testStartupHostFailWrongActionInProgress() {
@@ -212,7 +212,7 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"power_action\":\"shutdown\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertFalse(api.startupHost("ubuntu"));
+      assertFalse(api.startup("ubuntu"));
    }
    
    public void testShutdownHost() {
@@ -225,7 +225,7 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"power_action\":\"shutdown\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertTrue(api.shutdownHost("ubuntu"));
+      assertTrue(api.shutdown("ubuntu"));
    }
    
    public void testRebootHost() {
@@ -238,6 +238,6 @@
             HttpResponse.builder().statusCode(200)
                   .payload(payloadFromStringWithContentType("{\"host\":\"ubuntu\",\"power_action\":\"reboot\"}", MediaType.APPLICATION_JSON))
                   .build()).getHostAdministrationExtensionForZone("az-1.region-a.geo-1").get();
-      assertTrue(api.rebootHost("ubuntu"));
+      assertTrue(api.reboot("ubuntu"));
    }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApiLiveTest.java
index 20ce931..d9f0fe8 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAdministrationApiLiveTest.java
@@ -65,10 +65,10 @@
    public void testListAndGet() throws Exception {
       if (optApi.isPresent()) {
          HostAdministrationApi api = optApi.get();
-         Set<? extends Host> hosts = api.listHosts();
+         Set<? extends Host> hosts = api.list().toImmutableSet();
          assertNotNull(hosts);
          for (Host host : hosts) {
-            for (HostResourceUsage usage : api.getHostResourceUsage(host.getName())) {
+            for (HostResourceUsage usage : api.listResourceUsage(host.getName())) {
                assertEquals(usage.getHost(), host.getName());
                assertNotNull(usage);
             }
@@ -80,10 +80,10 @@
    public void testEnableDisable() throws Exception {
       if (optApi.isPresent()) {
          HostAdministrationApi api = optApi.get();
-         Host host = Iterables.find(api.listHosts(), isComputeHost);
+         Host host = Iterables.find(api.list(), isComputeHost);
 
-         assertTrue(api.disableHost(host.getName()));
-         assertTrue(api.enableHost(host.getName()));
+         assertTrue(api.disable(host.getName()));
+         assertTrue(api.enable(host.getName()));
       }
    }
 
@@ -91,9 +91,9 @@
    public void testMaintenanceMode() throws Exception {
       if (optApi.isPresent()) {
          HostAdministrationApi api = optApi.get();
-         Host host = Iterables.find(api.listHosts(), isComputeHost);
-         assertTrue(api.startHostMaintenance(host.getName()));
-         assertTrue(api.stopHostMaintenance(host.getName()));
+         Host host = Iterables.find(api.list(), isComputeHost);
+         assertTrue(api.startMaintenance(host.getName()));
+         assertTrue(api.stopMaintenance(host.getName()));
       }
    }
 
@@ -101,8 +101,8 @@
    public void testReboot() throws Exception {
       if (optApi.isPresent()) {
          HostAdministrationApi api = optApi.get();
-         Host host = Iterables.find(api.listHosts(), isComputeHost);
-         assertTrue(api.rebootHost(host.getName()));
+         Host host = Iterables.find(api.list(), isComputeHost);
+         assertTrue(api.reboot(host.getName()));
       }
    }
 
@@ -110,9 +110,9 @@
    public void testShutdownAndStartup() throws Exception {
       if (optApi.isPresent()) {
          HostAdministrationApi api = optApi.get();
-         Host host = Iterables.find(api.listHosts(), isComputeHost);
-         assertTrue(api.shutdownHost(host.getName()));
-         assertTrue(api.startupHost(host.getName()));
+         Host host = Iterables.find(api.list(), isComputeHost);
+         assertTrue(api.shutdown(host.getName()));
+         assertTrue(api.startup(host.getName()));
       }
    }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApiExpectTest.java
index 55997fb..f84c934 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApiExpectTest.java
@@ -54,7 +54,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/host_aggregate_list.json")).build())
             .getHostAggregateExtensionForZone("az-1.region-a.geo-1").get();
 
-      HostAggregate result = Iterables.getOnlyElement(api.listAggregates());
+      HostAggregate result = Iterables.getOnlyElement(api.list());
       assertEquals(result, exampleHostAggregate());
    }
 
@@ -66,7 +66,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/host_aggregate_with_host_details.json")).build())
             .getHostAggregateExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertEquals(api.getAggregate("1"), exampleHostAggregateWithHost());
+      assertEquals(api.get("1"), exampleHostAggregateWithHost());
    }
 
    public void testGetFailNotFound() {
@@ -76,7 +76,7 @@
             authenticatedGET().endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(404).build()).getHostAggregateExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertNull(api.getAggregate("1"));
+      assertNull(api.get("1"));
    }
 
    public void testCreateAggregate() {
@@ -89,7 +89,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/host_aggregate_details.json")).build())
             .getHostAggregateExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertEquals(api.createAggregate("ubuntu1", "nova"), exampleHostAggregate());
+      assertEquals(api.createInAvailabilityZone("ubuntu1", "nova"), exampleHostAggregate());
    }
 
    public void testDeleteAggregate() {
@@ -99,7 +99,7 @@
             authenticatedGET().endpoint(endpoint).method("DELETE").build(),
             HttpResponse.builder().statusCode(200).build()).getHostAggregateExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.deleteAggregate("1"));
+      assertTrue(api.delete("1"));
    }
 
    public void testDeleteAggregateFailNotFound() {
@@ -109,7 +109,7 @@
             authenticatedGET().endpoint(endpoint).method("DELETE").build(),
             HttpResponse.builder().statusCode(404).build()).getHostAggregateExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.deleteAggregate("1"));
+      assertFalse(api.delete("1"));
    }
 
    public void testUpdateName() {
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApiLiveTest.java
index 566c2b3..339bbf9 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/HostAggregateApiLiveTest.java
@@ -28,8 +28,8 @@
 import org.jclouds.openstack.nova.v2_0.domain.Host;
 import org.jclouds.openstack.nova.v2_0.domain.HostAggregate;
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Optional;
@@ -49,7 +49,7 @@
 
    private HostAggregate testAggregate;
 
-   @BeforeGroups(groups = {"integration", "live"})
+   @BeforeClass(groups = {"integration", "live"})
    @Override
    public void setupContext() {
       super.setupContext();
@@ -58,19 +58,19 @@
       hostAdminOption = novaContext.getApi().getHostAdministrationExtensionForZone(zone);
    }
 
+   @AfterClass(groups = { "integration", "live" })
    @Override
-   @AfterGroups(groups = {"integration", "live"})
-   public void tearDown() {
+   protected void tearDownContext() {
       if (testAggregate != null) {
-         assertTrue(apiOption.get().deleteAggregate(testAggregate.getId()));
+         assertTrue(apiOption.get().delete(testAggregate.getId()));
       }
-      super.tearDown();
+      super.tearDownContext();
    }
 
    public void testCreateAggregate() {
       if (apiOption.isPresent()) {
          // TODO assuming "nova" availability zone is present
-         testAggregate = apiOption.get().createAggregate("jclouds-test-a", "nova");
+         testAggregate = apiOption.get().createInAvailabilityZone("jclouds-test-a", "nova");
       }
    }
 
@@ -78,13 +78,13 @@
    public void testListAndGetAggregate() {
       if (apiOption.isPresent()) {
          HostAggregateApi api = apiOption.get();
-         Set<? extends HostAggregate> aggregates = api.listAggregates();
+         Set<? extends HostAggregate> aggregates = api.list().toImmutableSet();
          for (HostAggregate aggregate : aggregates) {
             assertNotNull(aggregate.getId());
             assertNotNull(aggregate.getName());
             assertNotNull(aggregate.getAvailabilityZone());
 
-            HostAggregate details = api.getAggregate(aggregate.getId());
+            HostAggregate details = api.get(aggregate.getId());
             assertEquals(details.getId(), aggregate.getId());
             assertEquals(details.getName(), aggregate.getName());
             assertEquals(details.getAvailabilityZone(), aggregate.getAvailabilityZone());
@@ -110,7 +110,7 @@
             }
 
             // Re-fetch to double-check
-            details = api.getAggregate(testAggregate.getId());
+            details = api.get(testAggregate.getId());
             for (String key : theMetaData.keySet()) {
                assertEquals(details.getMetadata().get(key), theMetaData.get(key));
             }
@@ -123,7 +123,7 @@
    public void testModifyHosts() {
       if (apiOption.isPresent() && hostAdminOption.isPresent()) {
          HostAggregateApi api = apiOption.get();
-         Host host = Iterables.getFirst(hostAdminOption.get().listHosts(), null);
+         Host host = Iterables.getFirst(hostAdminOption.get().list(), null);
          assertNotNull(host);
 
          String host_id = host.getName();
@@ -136,7 +136,7 @@
             assertEquals(details.getHosts(), ImmutableSet.of(host_id));
 
             // re-fetch to double-check
-            details = api.getAggregate(testAggregate.getId());
+            details = api.get(testAggregate.getId());
             assertEquals(details.getHosts(), ImmutableSet.of(host_id));
 
             // TODO wait until status of aggregate isn't CHANGING (hostAdministration.shutdown?)
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApiExpectTest.java
index 5f215c3..74004a4 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApiExpectTest.java
@@ -40,45 +40,45 @@
 public class KeyPairApiExpectTest extends BaseNovaApiExpectTest {
 
    public void testListKeyPairsWhenResponseIs2xx() throws Exception {
-      HttpRequest listKeyPairs = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-keypairs")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listKeyPairsResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/keypair_list.json")).build();
 
       NovaApi apiWhenServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listKeyPairs, listKeyPairsResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list, listResponse);
 
       assertEquals(apiWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
       // NOTE this required a change to the KeyPair domain object toString method
-      assertEquals(apiWhenServersExist.getKeyPairExtensionForZone("az-1.region-a.geo-1").get().listKeyPairs().toString(),
+      assertEquals(apiWhenServersExist.getKeyPairExtensionForZone("az-1.region-a.geo-1").get().list().toString(),
             new ParseKeyPairListTest().expected().toString());
    }
 
    public void testListKeyPairsWhenResponseIs404() throws Exception {
-      HttpRequest listKeyPairs = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-keypairs")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listKeyPairsResponse = HttpResponse.builder().statusCode(404).build();
+      HttpResponse listResponse = HttpResponse.builder().statusCode(404).build();
 
       NovaApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listKeyPairs, listKeyPairsResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list, listResponse);
 
-      assertTrue(apiWhenNoServersExist.getKeyPairExtensionForZone("az-1.region-a.geo-1").get().listKeyPairs().isEmpty());
+      assertTrue(apiWhenNoServersExist.getKeyPairExtensionForZone("az-1.region-a.geo-1").get().list().isEmpty());
 
    }
 
    public void testCreateKeyPair() throws Exception {
-      HttpRequest createKeyPair = HttpRequest
+      HttpRequest create = HttpRequest
             .builder()
             .method("POST")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-keypairs")
@@ -87,19 +87,19 @@
             .payload(payloadFromStringWithContentType("{\"keypair\":{\"name\":\"testkeypair\"}}", "application/json"))
             .build();
 
-      HttpResponse createKeyPairResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse createResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/keypair_created.json")).build();
 
       NovaApi apiWhenServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createKeyPair, createKeyPairResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, create, createResponse);
 
-      assertEquals(apiWhenServersExist.getKeyPairExtensionForZone("az-1.region-a.geo-1").get().createKeyPair("testkeypair")
+      assertEquals(apiWhenServersExist.getKeyPairExtensionForZone("az-1.region-a.geo-1").get().create("testkeypair")
             .toString(), new ParseKeyPairTest().expected().toString());
 
    }
 
    public void testCreateKeyPairWithPublicKey() throws Exception {
-      HttpRequest createKeyPair = HttpRequest
+      HttpRequest create = HttpRequest
             .builder()
             .method("POST")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-keypairs")
@@ -110,35 +110,35 @@
                         "{\"keypair\":{\"name\":\"testkeypair\",\"public_key\":\"ssh-rsa AAAXB3NzaC1yc2EAAAADAQABAAAAgQDFNyGjgs6c9akgmZ2ou/fJf7Pdrc23hC95/gM/33OrG4GZABACE4DTioa/PGN+7rHv9YUavUCtXrWayhGniKq/wCuI5fo5TO4AmDNv7/sCGHIHFumADSIoLx0vFhGJIetXEWxL9r0lfFC7//6yZM2W3KcGjbMtlPXqBT9K9PzdyQ== nova@nv-aw2az1-api0001\n\"}}",
                         "application/json")).build();
 
-      HttpResponse createKeyPairResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse createResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/keypair_created.json")).build();
 
       NovaApi apiWhenServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createKeyPair, createKeyPairResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, create, createResponse);
 
       assertEquals(
             apiWhenServersExist
                   .getKeyPairExtensionForZone("az-1.region-a.geo-1")
                   .get()
-                  .createKeyPairWithPublicKey(
+                  .createWithPublicKey(
                         "testkeypair",
                         "ssh-rsa AAAXB3NzaC1yc2EAAAADAQABAAAAgQDFNyGjgs6c9akgmZ2ou/fJf7Pdrc23hC95/gM/33OrG4GZABACE4DTioa/PGN+7rHv9YUavUCtXrWayhGniKq/wCuI5fo5TO4AmDNv7/sCGHIHFumADSIoLx0vFhGJIetXEWxL9r0lfFC7//6yZM2W3KcGjbMtlPXqBT9K9PzdyQ== nova@nv-aw2az1-api0001\n")
                   .toString(), new ParseKeyPairTest().expected().toString());
    }
 
    public void testDeleteKeyPair() throws Exception {
-      HttpRequest deleteKeyPair = HttpRequest
+      HttpRequest delete = HttpRequest
             .builder()
             .method("DELETE")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-keypairs/testkeypair")
             .addHeader("Accept", "*/*")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse deleteKeyPairResponse = HttpResponse.builder().statusCode(202).build();
+      HttpResponse deleteResponse = HttpResponse.builder().statusCode(202).build();
 
       NovaApi apiWhenServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, deleteKeyPair, deleteKeyPairResponse);
+            responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, delete, deleteResponse);
 
-      assertTrue(apiWhenServersExist.getKeyPairExtensionForZone("az-1.region-a.geo-1").get().deleteKeyPair("testkeypair"));
+      assertTrue(apiWhenServersExist.getKeyPairExtensionForZone("az-1.region-a.geo-1").get().delete("testkeypair"));
    }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApiLiveTest.java
index e8f2837..4bb91ef 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/KeyPairApiLiveTest.java
@@ -20,13 +20,12 @@
 
 import static org.testng.Assert.assertNotNull;
 
-import java.util.Map;
-import java.util.Set;
-
 import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.FluentIterable;
+
 /**
  * Tests behavior of {@code KeyPairApi}
  * 
@@ -38,7 +37,7 @@
    public void testListKeyPairs() throws Exception {
       for (String zoneId : novaContext.getApi().getConfiguredZones()) {
          KeyPairApi api = novaContext.getApi().getKeyPairExtensionForZone(zoneId).get();
-         Set<? extends Map<String, ? extends KeyPair>> keyPairsList = api.listKeyPairs();
+         FluentIterable<? extends KeyPair> keyPairsList = api.list();
          assertNotNull(keyPairsList);
       }
    }
@@ -49,11 +48,11 @@
          KeyPairApi api = novaContext.getApi().getKeyPairExtensionForZone(zoneId).get();
          KeyPair keyPair = null;
          try {
-            keyPair = api.createKeyPair(KEYPAIR_NAME);
+            keyPair = api.create(KEYPAIR_NAME);
             assertNotNull(keyPair);
          } finally {
             if (keyPair != null) {
-               api.deleteKeyPair(KEYPAIR_NAME);
+               api.delete(KEYPAIR_NAME);
             }
          }
       }
@@ -67,11 +66,11 @@
          KeyPairApi api = novaContext.getApi().getKeyPairExtensionForZone(zoneId).get();
          KeyPair keyPair = null;
          try {
-            keyPair = api.createKeyPairWithPublicKey(KEYPAIR_NAME, PUBLIC_KEY);
+            keyPair = api.createWithPublicKey(KEYPAIR_NAME, PUBLIC_KEY);
             assertNotNull(keyPair);
          } finally {
             if (keyPair != null) {
-               api.deleteKeyPair(KEYPAIR_NAME);
+               api.delete(KEYPAIR_NAME);
             }
          }
       }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApiExpectTest.java
index b3e31ae..b28a35f 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApiExpectTest.java
@@ -28,7 +28,7 @@
 
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
-import org.jclouds.openstack.nova.v2_0.domain.Quotas;
+import org.jclouds.openstack.nova.v2_0.domain.Quota;
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
 import org.jclouds.rest.ResourceNotFoundException;
 import org.testng.annotations.Test;
@@ -48,7 +48,7 @@
             authenticatedGET().endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/quotas.json")).build()).getQuotaExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertEquals(api.getQuotasForTenant("demo"), getTestQuotas());
+      assertEquals(api.getByTenant("demo"), getTestQuotas());
    }
 
    public void testGetQuotasFailsTenantNotFound() throws Exception {
@@ -57,7 +57,7 @@
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             authenticatedGET().endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(404).build()).getQuotaExtensionForZone("az-1.region-a.geo-1").get();
-      assertNull(api.getQuotasForTenant("demo"));
+      assertNull(api.getByTenant("demo"));
    }
 
    public void testGetDefaultQuotas() throws Exception {
@@ -67,7 +67,7 @@
             authenticatedGET().endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/quotas.json")).build()).getQuotaExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertEquals(api.getDefaultQuotasForTenant("demo"), getTestQuotas());
+      assertEquals(api.getDefaultsForTenant("demo"), getTestQuotas());
    }
 
    public void testGetDefaultQuotasFailsTenantNotFound() throws Exception {
@@ -76,7 +76,7 @@
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             authenticatedGET().endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(404).build()).getQuotaExtensionForZone("az-1.region-a.geo-1").get();
-      assertNull(api.getDefaultQuotasForTenant("demo"));
+      assertNull(api.getDefaultsForTenant("demo"));
    }
 
 
@@ -90,7 +90,7 @@
                   .build(),
             HttpResponse.builder().statusCode(200).build()).getQuotaExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.updateQuotasForTenant("demo", getTestQuotas()));
+      assertTrue(api.updateQuotaOfTenant(getTestQuotas(), "demo"));
    }
 
    @Test(expectedExceptions = ResourceNotFoundException.class)
@@ -104,11 +104,11 @@
                   .build(),
             HttpResponse.builder().statusCode(404).build()).getQuotaExtensionForZone("az-1.region-a.geo-1").get();
 
-      api.updateQuotasForTenant("demo", getTestQuotas());
+      api.updateQuotaOfTenant(getTestQuotas(), "demo");
    }
 
-   public static Quotas getTestQuotas() {
-      return Quotas.builder()
+   public static Quota getTestQuotas() {
+      return Quota.builder()
             .metadataItems(128)
             .injectedFileContentBytes(10240)
             .injectedFiles(5)
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApiLiveTest.java
index efd88d7..2cb2bb2 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaApiLiveTest.java
@@ -21,7 +21,7 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
-import org.jclouds.openstack.nova.v2_0.domain.Quotas;
+import org.jclouds.openstack.nova.v2_0.domain.Quota;
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
@@ -50,14 +50,14 @@
 
    public void testGetQuotasForCurrentTenant() {
       if (apiOption.isPresent()) {
-         Quotas quota = apiOption.get().getQuotasForTenant(tenant);
+         Quota quota = apiOption.get().getByTenant(tenant);
          assertQuotasIsValid(quota);
       }
    }
 
    public void testGetDefaultQuotasForCurrentTenant() {
       if (apiOption.isPresent()) {
-         Quotas quota = apiOption.get().getDefaultQuotasForTenant(tenant);
+         Quota quota = apiOption.get().getDefaultsForTenant(tenant);
          assertQuotasIsValid(quota);
       }
    }
@@ -65,28 +65,28 @@
    public void testUpdateQuotasOfCurrentTenantThenReset() {
       if (apiOption.isPresent()) {
          QuotaApi api = apiOption.get();
-         Quotas before = api.getQuotasForTenant(tenant);
+         Quota before = api.getByTenant(tenant);
          assertQuotasIsValid(before);
 
-         Quotas modified = before.toBuilder()
+         Quota modified = before.toBuilder()
                .cores(before.getCores() - 1)
                .instances(before.getInstances() - 1)
-               .metadataItems(before.getMetadataItems() - 1)
+               .metadataItems(before.getMetadatas() - 1)
                .ram(before.getRam() - 1)
                .volumes(before.getVolumes() - 1)
                .build();
 
-         assertTrue(api.updateQuotasForTenant(tenant, modified));
+         assertTrue(api.updateQuotaOfTenant(modified, tenant));
 
-         assertEquals(api.getQuotasForTenant(tenant), modified);
+         assertEquals(api.getByTenant(tenant), modified);
 
-         assertTrue(api.updateQuotasForTenant(tenant, before));
+         assertTrue(api.updateQuotaOfTenant(before, tenant));
 
-         assertEquals(api.getQuotasForTenant(tenant), before);
+         assertEquals(api.getByTenant(tenant), before);
       }
    }
 
-   protected void assertQuotasIsValid(Quotas quota) {
+   protected void assertQuotasIsValid(Quota quota) {
       assertTrue(quota.getCores() > 0);
       assertTrue(quota.getFloatingIps() >= 0);
       assertTrue(quota.getGigabytes() > 0);
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApiExpectTest.java
index 0a8ca1a..612c73f 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApiExpectTest.java
@@ -48,7 +48,7 @@
             authenticatedGET().endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/quota_class.json")).build()).getQuotaClassExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertEquals(api.getQuotaClass("jcloudstestquotas"), getTestQuotas());
+      assertEquals(api.get("jcloudstestquotas"), getTestQuotas());
    }
 
    public void testGetQuotasFailsTenantNotFound() throws Exception {
@@ -57,7 +57,7 @@
             responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse,
             authenticatedGET().endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(404).build()).getQuotaClassExtensionForZone("az-1.region-a.geo-1").get();
-      assertNull(api.getQuotaClass("jcloudstestquotas"));
+      assertNull(api.get("jcloudstestquotas"));
    }
 
    public void testUpdateQuotas() throws Exception {
@@ -70,7 +70,7 @@
                   .build(),
             HttpResponse.builder().statusCode(200).build()).getQuotaClassExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.updateQuotaClass("myclass", getTestQuotas()));
+      assertTrue(api.update("myclass", getTestQuotas()));
    }
 
    @Test(expectedExceptions = ResourceNotFoundException.class)
@@ -84,7 +84,7 @@
                   .build(),
             HttpResponse.builder().statusCode(404).build()).getQuotaClassExtensionForZone("az-1.region-a.geo-1").get();
 
-      api.updateQuotaClass("jcloudstestquotas", getTestQuotas());
+      api.update("jcloudstestquotas", getTestQuotas());
    }
 
    public static QuotaClass getTestQuotas() {
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApiLiveTest.java
index d5b80da..dd79198 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/QuotaClassApiLiveTest.java
@@ -60,16 +60,16 @@
                      .volumes(5)
                      .build();
 
-         assertTrue(api.updateQuotaClass(firstVersion.getId(), firstVersion));
+         assertTrue(api.update(firstVersion.getId(), firstVersion));
 
-         assertEquals(api.getQuotaClass(firstVersion.getId()), firstVersion);
+         assertEquals(api.get(firstVersion.getId()), firstVersion);
 
          // Change it again (since we may have run this test before and we can't delete the QuotaClass)
          QuotaClass secondVersion = firstVersion.toBuilder().ram(8192).build();
 
-         assertTrue(api.updateQuotaClass(secondVersion.getId(), secondVersion));
+         assertTrue(api.update(secondVersion.getId(), secondVersion));
 
-         assertEquals(api.getQuotaClass(secondVersion.getId()), secondVersion);
+         assertEquals(api.get(secondVersion.getId()), secondVersion);
       }
    }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApiExpectTest.java
index cf978e2..b76249c 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApiExpectTest.java
@@ -47,22 +47,22 @@
 @Test(groups = "unit", testName = "SecurityGroupApiExpectTest")
 public class SecurityGroupApiExpectTest extends BaseNovaApiExpectTest {
    public void testListSecurityGroupsWhenResponseIs2xx() throws Exception {
-      HttpRequest listSecurityGroups = HttpRequest.builder().method("GET").endpoint(
+      HttpRequest list = HttpRequest.builder().method("GET").endpoint(
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers(
                ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                         authToken).build()).build();
 
-      HttpResponse listSecurityGroupsResponse = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/securitygroup_list.json")).build();
 
       NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listSecurityGroups,
-               listSecurityGroupsResponse);
+               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list,
+               listResponse);
 
       assertEquals(apiWhenSecurityGroupsExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
       assertEquals(apiWhenSecurityGroupsExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .listSecurityGroups().toString(), new ParseSecurityGroupListTest().expected().toString());
+               .list().toString(), new ParseSecurityGroupListTest().expected().toString());
    }
 
    public void testListSecurityGroupsWhenReponseIs404IsEmpty() throws Exception {
@@ -78,7 +78,7 @@
                listListSecurityGroupsResponse);
 
       assertTrue(apiWhenNoSecurityGroupsExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .listSecurityGroups().isEmpty());
+               .list().isEmpty());
    }
 
    public void testGetSecurityGroupWhenResponseIs2xx() throws Exception {
@@ -96,7 +96,7 @@
                getSecurityGroupResponse);
 
       assertEquals(apiWhenSecurityGroupsExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .getSecurityGroup("0").toString(), new ParseSecurityGroupTest().expected().toString());
+               .get("0").toString(), new ParseSecurityGroupTest().expected().toString());
    }
 
    public void testGetSecurityGroupWhenResponseIs404() throws Exception {
@@ -112,12 +112,12 @@
                getSecurityGroupResponse);
 
       assertNull(apiWhenNoSecurityGroupsExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .getSecurityGroup("0"));
+               .get("0"));
 
    }
 
    public void testCreateSecurityGroupWhenResponseIs2xx() throws Exception {
-      HttpRequest createSecurityGroup = HttpRequest.builder().method("POST").endpoint(
+      HttpRequest create = HttpRequest.builder().method("POST").endpoint(
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers(
                ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                         authToken).build())
@@ -126,38 +126,38 @@
                                  "{\"security_group\":{\"name\":\"jclouds-test\",\"description\":\"jclouds-test\"}}",
                                  "application/json")).build();
 
-      HttpResponse createSecurityGroupResponse = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse createResponse = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/securitygroup_created.json")).build();
 
       NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createSecurityGroup,
-               createSecurityGroupResponse);
+               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, create,
+               createResponse);
 
       assertEquals(apiWhenSecurityGroupsExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .createSecurityGroupWithNameAndDescription("jclouds-test", "jclouds-test").toString(),
-               createSecurityGroupExpected().toString());
+               .createWithDescription("jclouds-test", "jclouds-test").toString(),
+               createExpected().toString());
    }
 
    public void testDeleteSecurityGroupWhenResponseIs2xx() throws Exception {
-      HttpRequest deleteSecurityGroup = HttpRequest.builder().method("DELETE").endpoint(
+      HttpRequest delete = HttpRequest.builder().method("DELETE").endpoint(
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups/160"))
                .headers(
                         ImmutableMultimap.<String, String> builder().put("Accept", "application/json")
                                  .put("X-Auth-Token", authToken).build()).build();
 
-      HttpResponse deleteSecurityGroupResponse = HttpResponse.builder().statusCode(202).build();
+      HttpResponse deleteResponse = HttpResponse.builder().statusCode(202).build();
 
       NovaApi apiWhenServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, deleteSecurityGroup,
-               deleteSecurityGroupResponse);
+               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, delete,
+               deleteResponse);
 
       assertTrue(apiWhenServersExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .deleteSecurityGroup("160"));
+               .delete("160"));
 
    }
 
    public void testCreateSecurityGroupRuleForCidrBlockWhenResponseIs2xx() throws Exception {
-      HttpRequest createSecurityGroupRule = HttpRequest
+      HttpRequest createRule = HttpRequest
                .builder()
                .method("POST")
                .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-group-rules")
@@ -168,21 +168,21 @@
                                  "{\"security_group_rule\":{\"parent_group_id\":\"161\",\"cidr\":\"0.0.0.0/0\",\"ip_protocol\":\"tcp\",\"from_port\":\"80\",\"to_port\":\"8080\"}}",
                                  "application/json")).build();
 
-      HttpResponse createSecurityGroupRuleResponse = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse createRuleResponse = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/securitygrouprule_created.json")).build();
 
       NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createSecurityGroupRule,
-               createSecurityGroupRuleResponse);
+               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createRule,
+               createRuleResponse);
 
       assertEquals(apiWhenSecurityGroupsExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .createSecurityGroupRuleAllowingCidrBlock("161",
+               .createRuleAllowingCidrBlock("161",
                         Ingress.builder().ipProtocol(IpProtocol.TCP).fromPort(80).toPort(8080).build(), "0.0.0.0/0")
-               .toString(), createSecurityGroupRuleExpected().toString());
+               .toString(), createRuleExpected().toString());
    }
    
    public void testCreateSecurityGroupRuleForSecurityGroupIdWhenResponseIs2xx() throws Exception {
-      HttpRequest createSecurityGroupRule = HttpRequest
+      HttpRequest createRule = HttpRequest
                .builder()
                .method("POST")
                .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-group-rules")
@@ -193,43 +193,43 @@
                                  "{\"security_group_rule\":{\"group_id\":\"999\",\"parent_group_id\":\"161\",\"ip_protocol\":\"tcp\",\"from_port\":\"80\",\"to_port\":\"8080\"}}",
                                  "application/json")).build();
 
-      HttpResponse createSecurityGroupRuleResponse = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse createRuleResponse = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/securitygrouprule_created.json")).build();
 
       NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createSecurityGroupRule,
-               createSecurityGroupRuleResponse);
+               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, createRule,
+               createRuleResponse);
 
       assertEquals(apiWhenSecurityGroupsExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .createSecurityGroupRuleAllowingSecurityGroupId("161",
+               .createRuleAllowingSecurityGroupId("161",
                         Ingress.builder().ipProtocol(IpProtocol.TCP).fromPort(80).toPort(8080).build(), "999")
-               .toString(), createSecurityGroupRuleExpected().toString());
+               .toString(), createRuleExpected().toString());
    }
 
    public void testDeleteSecurityGroupRuleWhenResponseIs2xx() throws Exception {
-      HttpRequest deleteSecurityGroupRule = HttpRequest.builder().method("DELETE").endpoint(
+      HttpRequest deleteRule = HttpRequest.builder().method("DELETE").endpoint(
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-group-rules/161"))
                .headers(
                         ImmutableMultimap.<String, String> builder().put("Accept", "*/*")
                                  .put("X-Auth-Token", authToken).build()).build();
 
-      HttpResponse deleteSecurityGroupRuleResponse = HttpResponse.builder().statusCode(202).build();
+      HttpResponse deleteRuleResponse = HttpResponse.builder().statusCode(202).build();
 
       NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, deleteSecurityGroupRule,
-               deleteSecurityGroupRuleResponse);
+               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, deleteRule,
+               deleteRuleResponse);
 
       assertTrue(apiWhenSecurityGroupsExist.getSecurityGroupExtensionForZone("az-1.region-a.geo-1").get()
-               .deleteSecurityGroupRule("161"));
+               .deleteRule("161"));
 
    }
 
-   private SecurityGroup createSecurityGroupExpected() {
+   private SecurityGroup createExpected() {
       return SecurityGroup.builder().description("jclouds-test").id("160").name("jclouds-test").rules(
                ImmutableSet.<SecurityGroupRule> of()).tenantId("dev_16767499955063").build();
    }
 
-   private SecurityGroupRule createSecurityGroupRuleExpected() {
+   private SecurityGroupRule createRuleExpected() {
       return SecurityGroupRule.builder().fromPort(80).id("218").ipProtocol(
                IpProtocol.TCP).ipRange("0.0.0.0/0").parentGroupId("161").toPort(8080).build();
    }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApiLiveTest.java
index e6a5a57..b3555bc 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SecurityGroupApiLiveTest.java
@@ -41,10 +41,10 @@
 
    public static final String SECURITY_GROUP_NAME = "testsg";
 
-   public void listSecurityGroups() throws Exception {
+   public void list() throws Exception {
       for (String zoneId : novaContext.getApi().getConfiguredZones()) {
          SecurityGroupApi api = novaContext.getApi().getSecurityGroupExtensionForZone(zoneId).get();
-         Set<? extends SecurityGroup> securityGroupsList = api.listSecurityGroups();
+         Set<? extends SecurityGroup> securityGroupsList = api.list().toImmutableSet();
          assertNotNull(securityGroupsList);
       }
    }
@@ -56,14 +56,14 @@
          String id;
          try {
             securityGroup = api
-                     .createSecurityGroupWithNameAndDescription(SECURITY_GROUP_NAME, "test security group");
+                     .createWithDescription(SECURITY_GROUP_NAME, "test security group");
             assertNotNull(securityGroup);
             id = securityGroup.getId();
-            SecurityGroup theGroup = api.getSecurityGroup(id);
+            SecurityGroup theGroup = api.get(id);
             assertNotNull(theGroup);
          } finally {
             if (securityGroup != null) {
-               api.deleteSecurityGroup(securityGroup.getId());
+               api.delete(securityGroup.getId());
             }
          }
       }
@@ -75,25 +75,25 @@
          SecurityGroup securityGroup = null;
 
          try {
-            securityGroup = api.createSecurityGroupWithNameAndDescription(SECURITY_GROUP_NAME, "test security group");
+            securityGroup = api.createWithDescription(SECURITY_GROUP_NAME, "test security group");
             assertNotNull(securityGroup);
 
             for (int port : ImmutableSet.of(22, 8080)) {
-               SecurityGroupRule rule = api.createSecurityGroupRuleAllowingCidrBlock(securityGroup.getId(), Ingress
+               SecurityGroupRule rule = api.createRuleAllowingCidrBlock(securityGroup.getId(), Ingress
                         .builder().ipProtocol(IpProtocol.TCP).fromPort(port).toPort(port).build(), "0.0.0.0/0");
                assertNotNull(rule);
 
-               SecurityGroupRule rule2 = api.createSecurityGroupRuleAllowingSecurityGroupId(securityGroup.getId(),
+               SecurityGroupRule rule2 = api.createRuleAllowingSecurityGroupId(securityGroup.getId(),
                         Ingress.builder().ipProtocol(IpProtocol.TCP).fromPort(port).toPort(port).build(), securityGroup
                                  .getId());
 
                assertNotNull(rule2);
             }
-            securityGroup = api.getSecurityGroup(securityGroup.getId());
+            securityGroup = api.get(securityGroup.getId());
 
          } finally {
             if (securityGroup != null) {
-               api.deleteSecurityGroup(securityGroup.getId());
+               api.delete(securityGroup.getId());
             }
          }
       }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApiExpectTest.java
index 8c06d5b..e9551c0 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApiExpectTest.java
@@ -47,7 +47,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_with_security_groups.json")).build()
       ).getServerWithSecurityGroupsExtensionForZone("az-1.region-a.geo-1").get();
 
-      ServerWithSecurityGroups server = api.getServer("8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
+      ServerWithSecurityGroups server = api.get("8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
       assertEquals(server.getId(), "8d0a6ca5-8849-4b3d-b86e-f24c92490ebb");
       assertEquals(server.getSecurityGroupNames(), ImmutableSet.of("default", "group1"));
    }
@@ -60,6 +60,6 @@
             authenticatedGET().endpoint(endpoint).build(),
             HttpResponse.builder().statusCode(404).build()
       ).getServerWithSecurityGroupsExtensionForZone("az-1.region-a.geo-1").get();
-      assertNull(api.getServer("8d0a6ca5-8849-4b3d-b86e-f24c92490ebb"));
+      assertNull(api.get("8d0a6ca5-8849-4b3d-b86e-f24c92490ebb"));
    }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApiLiveTest.java
index 533ac32..4254a1d 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/ServerWithSecurityGroupsApiLiveTest.java
@@ -56,8 +56,8 @@
    public void testGetServer() {
       if (apiOption.isPresent()) {
 
-         for (Resource server : serverApi.listServers()) {
-            ServerWithSecurityGroups serverWithGroups = apiOption.get().getServer(server.getId());
+         for (Resource server : serverApi.list().concat()) {
+            ServerWithSecurityGroups serverWithGroups = apiOption.get().get(server.getId());
             assertEquals(serverWithGroups.getId(), server.getId());
             assertEquals(serverWithGroups.getName(), server.getName());
             assertNotNull(serverWithGroups.getSecurityGroupNames());
@@ -68,12 +68,12 @@
          try {
             testServer = createServerInZone(zone);
             
-            ServerWithSecurityGroups results = apiOption.get().getServer(testServer.getId());
+            ServerWithSecurityGroups results = apiOption.get().get(testServer.getId());
             assertEquals(results.getId(), testServer.getId());
             assertEquals(results.getSecurityGroupNames(), ImmutableSet.of("default"));
          } finally {
             if (testServer != null) {
-               serverApi.deleteServer(testServer.getId());
+               serverApi.delete(testServer.getId());
             }
          }
       }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApiExpectTest.java
index e158655..d99e66b 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApiExpectTest.java
@@ -58,7 +58,7 @@
                   .payload(payloadFromResource("/simple_tenant_usages.json")).build())
             .getSimpleTenantUsageExtensionForZone("az-1.region-a.geo-1").get();
       
-      Set<? extends SimpleTenantUsage> results = api.listTenantUsages();
+      Set<? extends SimpleTenantUsage> results = api.list().toImmutableSet();
       
       SimpleTenantUsage usage = Iterables.getOnlyElement(results);
       assertEquals(usage.getTenantId(), "f8535069c3fb404cb61c873b1a0b4921");
@@ -84,7 +84,7 @@
                   .payload(payloadFromResource("/simple_tenant_usage.json")).build())
             .getSimpleTenantUsageExtensionForZone("az-1.region-a.geo-1").get();
 
-      SimpleTenantUsage usage = api.getTenantUsage("test-1234");
+      SimpleTenantUsage usage = api.get("test-1234");
       assertEquals(usage.getTenantId(), "f8535069c3fb404cb61c873b1a0b4921");
       
       SimpleTenantUsage expected = SimpleTenantUsage.builder().tenantId("f8535069c3fb404cb61c873b1a0b4921").totalHours(4.833333333333333E-7).totalLocalGbUsage(1.933333333333333E-05)
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApiLiveTest.java
index 4fe7a30..887481a 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/SimpleTenantUsageApiLiveTest.java
@@ -41,10 +41,10 @@
          Optional<? extends SimpleTenantUsageApi> optApi = novaContext.getApi().getSimpleTenantUsageExtensionForZone(zoneId);
          if (optApi.isPresent() && identity.endsWith(":admin")) {
             SimpleTenantUsageApi api = optApi.get();
-            Set<? extends SimpleTenantUsage> usages = api.listTenantUsages();
+            Set<? extends SimpleTenantUsage> usages = api.list().toImmutableSet();
             assertNotNull(usages);
             for (SimpleTenantUsage usage : usages) {
-               SimpleTenantUsage details = api.getTenantUsage(usage.getTenantId());
+               SimpleTenantUsage details = api.get(usage.getTenantId());
                assertNotNull(details);
             }
          }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApiExpectTest.java
index be03ed6..b3dfefe 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApiExpectTest.java
@@ -47,7 +47,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/virtual_interfaces_list.json")).build()
       ).getVirtualInterfaceExtensionForZone("az-1.region-a.geo-1").get();
 
-      VirtualInterface vif = Iterables.getOnlyElement(api.listVirtualInterfacesForServer("1"));
+      VirtualInterface vif = Iterables.getOnlyElement(api.listOnServer("1"));
       assertEquals(vif.getId(), "02315827-b05c-4668-9c05-75c68838074a");
       assertEquals(vif.getMacAddress(), "fa:16:3e:09:71:34");
    }
@@ -61,6 +61,6 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVirtualInterfaceExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.listVirtualInterfacesForServer("1").isEmpty());
+      assertTrue(api.listOnServer("1").isEmpty());
    }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApiLiveTest.java
index f409ea1..8047bca 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VirtualInterfaceApiLiveTest.java
@@ -55,14 +55,14 @@
          Server testServer = null;
          try {
             testServer = createServerInZone(zone);
-            Set<? extends VirtualInterface> results = apiOption.get().listVirtualInterfacesForServer(testServer.getId());
+            Set<? extends VirtualInterface> results = apiOption.get().listOnServer(testServer.getId()).toImmutableSet();
             for (VirtualInterface vif : results) {
                assertNotNull(vif.getId());
                assertNotNull(vif.getMacAddress());
             }
          } finally {
             if (testServer != null) {
-               novaContext.getApi().getServerApiForZone(zone).deleteServer(testServer.getId());
+               novaContext.getApi().getServerApiForZone(zone).delete(testServer.getId());
             }
          }
    }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApiExpectTest.java
index 80bde50..25b036a 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApiExpectTest.java
@@ -62,7 +62,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_list.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends Volume> volumes = api.listVolumes();
+      Set<? extends Volume> volumes = api.list().toImmutableSet();
       assertEquals(volumes, ImmutableSet.of(testVolume()));
    }
 
@@ -75,7 +75,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends Volume> volumes = api.listVolumes();
+      Set<? extends Volume> volumes = api.list().toImmutableSet();
       assertTrue(volumes.isEmpty());
    }
 
@@ -88,7 +88,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_list_detail.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends Volume> volumes = api.listVolumesInDetail();
+      Set<? extends Volume> volumes = api.listInDetail().toImmutableSet();
       assertEquals(volumes, ImmutableSet.of(testVolume()));
    }
 
@@ -101,7 +101,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends Volume> volumes = api.listVolumesInDetail();
+      Set<? extends Volume> volumes = api.listInDetail().toImmutableSet();
       assertTrue(volumes.isEmpty());
    }
    
@@ -117,7 +117,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_details.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Volume volume = api.createVolume(1, CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume"));
+      Volume volume = api.create(1, CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume"));
       assertEquals(volume, testVolume());
    }
 
@@ -135,7 +135,7 @@
             HttpResponse.builder().statusCode(404).payload(payloadFromResource("/volume_details.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      api.createVolume(1, CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume"));
+      api.create(1, CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume"));
    }
 
    public void testGetVolume() {
@@ -147,7 +147,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_details.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Volume volume = api.getVolume("1");
+      Volume volume = api.get("1");
       assertEquals(volume, testVolume());
       // double-check equals()
       assertEquals(volume.getStatus(), Volume.Status.IN_USE);
@@ -167,7 +167,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertNull(api.getVolume("1"));
+      assertNull(api.get("1"));
    }
 
    public void testDeleteVolume() {
@@ -179,7 +179,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/attachment_details.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.deleteVolume("1"));
+      assertTrue(api.delete("1"));
    }
 
    public void testDeleteVolumeFail() {
@@ -191,7 +191,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.deleteVolume("1"));
+      assertFalse(api.delete("1"));
    }
 
    public void testListAttachments() {
@@ -203,7 +203,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/attachment_list.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends VolumeAttachment> attachments = api.listAttachmentsOnServer("instance-1");
+      Set<? extends VolumeAttachment> attachments = api.listAttachmentsOnServer("instance-1").toImmutableSet();
       assertEquals(attachments, ImmutableSet.of(testAttachment()));
       // double-check individual fields
       VolumeAttachment attachment = Iterables.getOnlyElement(attachments);
@@ -312,7 +312,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/snapshot_list.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends VolumeSnapshot> snapshots = api.listSnapshots();
+      Set<? extends VolumeSnapshot> snapshots = api.listSnapshots().toImmutableSet();
       assertEquals(snapshots, ImmutableSet.of(testSnapshot()));
    }
 
@@ -325,7 +325,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends VolumeSnapshot> snapshots = api.listSnapshots();
+      Set<? extends VolumeSnapshot> snapshots = api.listSnapshots().toImmutableSet();
       assertTrue(snapshots.isEmpty());
    }
 
@@ -363,7 +363,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/snapshot_list_detail.json")).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends VolumeSnapshot> snapshots = api.listSnapshotsInDetail();
+      Set<? extends VolumeSnapshot> snapshots = api.listSnapshotsInDetail().toImmutableSet();
       assertEquals(snapshots, ImmutableSet.of(testSnapshot()));
 
       // double-check individual fields
@@ -385,7 +385,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends VolumeSnapshot> snapshots = api.listSnapshotsInDetail();
+      Set<? extends VolumeSnapshot> snapshots = api.listSnapshotsInDetail().toImmutableSet();
       assertTrue(snapshots.isEmpty());
    }
    
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApiLiveTest.java
index fe10147..4e1efbf 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeApiLiveTest.java
@@ -31,8 +31,8 @@
 import org.jclouds.openstack.nova.v2_0.options.CreateVolumeOptions;
 import org.jclouds.openstack.nova.v2_0.options.CreateVolumeSnapshotOptions;
 import org.jclouds.predicates.RetryablePredicate;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Objects;
@@ -54,7 +54,7 @@
    private Volume testVolume;
    private VolumeSnapshot testSnapshot;
 
-   @BeforeGroups(groups = { "integration", "live" })
+   @BeforeClass(groups = {"integration", "live"})
    @Override
    public void setupContext() {
       super.setupContext();
@@ -62,9 +62,9 @@
       volumeOption = novaContext.getApi().getVolumeExtensionForZone(zone);
    }
 
-   @AfterGroups(groups = "live", alwaysRun = true)
+   @AfterClass(groups = { "integration", "live" })
    @Override
-   protected void tearDown() {
+   protected void tearDownContext() {
       if (volumeOption.isPresent()) {
          if (testSnapshot != null) {
             final String snapshotId = testSnapshot.getId();
@@ -78,28 +78,28 @@
          }
          if (testVolume != null) {
             final String volumeId = testVolume.getId();
-            assertTrue(volumeOption.get().deleteVolume(volumeId));
+            assertTrue(volumeOption.get().delete(volumeId));
             assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
                @Override
                public boolean apply(VolumeApi volumeApi) {
-                  return volumeOption.get().getVolume(volumeId) == null;
+                  return volumeOption.get().get(volumeId) == null;
                }
             }, 180 * 1000L).apply(volumeOption.get()));
          }
       }
-      super.tearDown();
+      super.tearDownContext();
    }
 
    public void testCreateVolume() {
       if (volumeOption.isPresent()) {
-         testVolume = volumeOption.get().createVolume(
+         testVolume = volumeOption.get().create(
                   1,
                   CreateVolumeOptions.Builder.name("jclouds-test-volume").description("description of test volume")
                            .availabilityZone(zone));
          assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
             @Override
             public boolean apply(VolumeApi volumeApi) {
-               return volumeOption.get().getVolume(testVolume.getId()).getStatus() == Volume.Status.AVAILABLE;
+               return volumeOption.get().get(testVolume.getId()).getStatus() == Volume.Status.AVAILABLE;
             }
          }, 180 * 1000L).apply(volumeOption.get()));
       }
@@ -108,28 +108,28 @@
    @Test(dependsOnMethods = "testCreateVolume")
    public void testListVolumes() {
       if (volumeOption.isPresent()) {
-         Set<? extends Volume> volumes = volumeOption.get().listVolumes();
+         Set<? extends Volume> volumes = volumeOption.get().list().toImmutableSet();
          assertNotNull(volumes);
          boolean foundIt = false;
          for (Volume vol : volumes) {
-            Volume details = volumeOption.get().getVolume(vol.getId());
+            Volume details = volumeOption.get().get(vol.getId());
             assertNotNull(details);
             if (Objects.equal(details.getId(), testVolume.getId())) {
                foundIt = true;
             }
          }
-         assertTrue(foundIt, "Failed to find the volume we created in listVolumes() response");
+         assertTrue(foundIt, "Failed to find the volume we created in list() response");
       }
    }
 
    @Test(dependsOnMethods = "testCreateVolume")
    public void testListVolumesInDetail() {
       if (volumeOption.isPresent()) {
-         Set<? extends Volume> volumes = volumeOption.get().listVolumesInDetail();
+         Set<? extends Volume> volumes = volumeOption.get().listInDetail().toImmutableSet();
          assertNotNull(volumes);
          boolean foundIt = false;
          for (Volume vol : volumes) {
-            Volume details = volumeOption.get().getVolume(vol.getId());
+            Volume details = volumeOption.get().get(vol.getId());
             assertNotNull(details);
             assertNotNull(details.getId());
             assertNotNull(details.getCreated());
@@ -144,7 +144,7 @@
                foundIt = true;
             }
          }
-         assertTrue(foundIt, "Failed to find the volume we previously created in listVolumesInDetail() response");
+         assertTrue(foundIt, "Failed to find the volume we previously created in listInDetail() response");
       }
    }
 
@@ -174,7 +174,7 @@
    @Test(dependsOnMethods = "testCreateSnapshot")
    public void testListSnapshots() {
       if (volumeOption.isPresent()) {
-         Set<? extends VolumeSnapshot> snapshots = volumeOption.get().listSnapshots();
+         Set<? extends VolumeSnapshot> snapshots = volumeOption.get().listSnapshots().toImmutableSet();
          assertNotNull(snapshots);
          boolean foundIt = false;
          for (VolumeSnapshot snap : snapshots) {
@@ -193,7 +193,7 @@
    @Test(dependsOnMethods = "testCreateSnapshot")
    public void testListSnapshotsInDetail() {
       if (volumeOption.isPresent()) {
-         Set<? extends VolumeSnapshot> snapshots = volumeOption.get().listSnapshotsInDetail();
+         Set<? extends VolumeSnapshot> snapshots = volumeOption.get().listSnapshotsInDetail().toImmutableSet();
          assertNotNull(snapshots);
          boolean foundIt = false;
          for (VolumeSnapshot snap : snapshots) {
@@ -225,7 +225,7 @@
          try {
             final String serverId = server_id = createServerInZone(zone).getId();
 
-            Set<? extends VolumeAttachment> attachments = volumeOption.get().listAttachmentsOnServer(serverId);
+            Set<? extends VolumeAttachment> attachments = volumeOption.get().listAttachmentsOnServer(serverId).toImmutableSet();
             assertNotNull(attachments);
             final int before = attachments.size();
 
@@ -241,11 +241,11 @@
                }
             }, 60 * 1000L).apply(volumeOption.get()));
 
-            attachments = volumeOption.get().listAttachmentsOnServer(serverId);
+            attachments = volumeOption.get().listAttachmentsOnServer(serverId).toImmutableSet();
             assertNotNull(attachments);
             assertEquals(attachments.size(), before + 1);
 
-            assertEquals(volumeOption.get().getVolume(testVolume.getId()).getStatus(), Volume.Status.IN_USE);
+            assertEquals(volumeOption.get().get(testVolume.getId()).getStatus(), Volume.Status.IN_USE);
 
             boolean foundIt = false;
             for (VolumeAttachment att : attachments) {
@@ -274,7 +274,7 @@
 
          } finally {
             if (server_id != null)
-               novaContext.getApi().getServerApiForZone(zone).deleteServer(server_id);
+               novaContext.getApi().getServerApiForZone(zone).delete(server_id);
          }
 
       }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApiExpectTest.java
index a62308a..24574ef 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApiExpectTest.java
@@ -57,7 +57,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type_list.json")).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      Set<? extends VolumeType> types = api.listVolumeTypes();
+      Set<? extends VolumeType> types = api.list().toImmutableSet();
       assertEquals(types, ImmutableSet.of(testVolumeType()));
    }
 
@@ -70,7 +70,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type.json")).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      VolumeType type = api.getVolumeType("8");
+      VolumeType type = api.get("8");
       assertEquals(type, testVolumeType());
    }
 
@@ -83,7 +83,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertNull(api.getVolumeType("8"));
+      assertNull(api.get("8"));
    }
 
    public void testCreateVolumeType() {
@@ -97,7 +97,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type.json")).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      VolumeType type = api.createVolumeType("jclouds-test-1");
+      VolumeType type = api.create("jclouds-test-1");
       assertEquals(type, testVolumeType());
    }
 
@@ -112,7 +112,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type.json")).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      VolumeType type = api.createVolumeType("jclouds-test-1", CreateVolumeTypeOptions.NONE);
+      VolumeType type = api.create("jclouds-test-1", CreateVolumeTypeOptions.NONE);
       assertEquals(type, testVolumeType());
    }
 
@@ -127,7 +127,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type.json")).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      VolumeType type = api.createVolumeType("jclouds-test-1", CreateVolumeTypeOptions.Builder.specs(ImmutableMap.of("x", "y")));
+      VolumeType type = api.create("jclouds-test-1", CreateVolumeTypeOptions.Builder.specs(ImmutableMap.of("x", "y")));
       assertEquals(type, testVolumeType());
    }
 
@@ -140,7 +140,7 @@
             HttpResponse.builder().statusCode(200).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.deleteVolumeType("8"));
+      assertTrue(api.delete("8"));
    }
 
    public void testDeleteVolumeTypeFailNotFound() {
@@ -152,7 +152,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertFalse(api.deleteVolumeType("8"));
+      assertFalse(api.delete("8"));
    }
 
    public void testGetAllExtraSpecs() {
@@ -164,7 +164,7 @@
             HttpResponse.builder().statusCode(200).payload(payloadFromResource("/volume_type_extra_specs.json")).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertEquals(api.getAllExtraSpecs("9"), ImmutableMap.of("test", "value1"));
+      assertEquals(api.getExtraSpecs("9"), ImmutableMap.of("test", "value1"));
    }
 
    public void testGetAllExtraSpecsFailNotFound() {
@@ -176,7 +176,7 @@
             HttpResponse.builder().statusCode(404).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.getAllExtraSpecs("9").isEmpty());
+      assertTrue(api.getExtraSpecs("9").isEmpty());
    }
 
    public void testSetAllExtraSpecs() {
@@ -190,7 +190,7 @@
             HttpResponse.builder().statusCode(200).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.setAllExtraSpecs("9", ImmutableMap.of("test1", "somevalue")));
+      assertTrue(api.updateExtraSpecs("9", ImmutableMap.of("test1", "somevalue")));
    }
 
    public void testSetExtraSpec() {
@@ -204,7 +204,7 @@
             HttpResponse.builder().statusCode(200).build()
       ).getVolumeTypeExtensionForZone("az-1.region-a.geo-1").get();
 
-      assertTrue(api.setExtraSpec("5", "test1", "somevalue"));
+      assertTrue(api.updateExtraSpec("5", "test1", "somevalue"));
    }
 
    public void testGetExtraSpec() {
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApiLiveTest.java
index 6d87e17..3733c4b 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/extensions/VolumeTypeApiLiveTest.java
@@ -28,7 +28,7 @@
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
 import org.jclouds.openstack.nova.v2_0.options.CreateVolumeTypeOptions;
 import org.jclouds.predicates.RetryablePredicate;
-import org.testng.annotations.AfterGroups;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeGroups;
 import org.testng.annotations.Test;
 
@@ -59,70 +59,71 @@
       volumeTypeOption = novaContext.getApi().getVolumeTypeExtensionForZone(zone);
    }
 
-   @AfterGroups(groups = "live")
+
+   @AfterClass(groups = { "integration", "live" })
    @Override
-   protected void tearDown() {
+   protected void tearDownContext() {
       if (volumeTypeOption.isPresent()) {
          if (testVolumeType != null) {
             final String id = testVolumeType.getId();
-            assertTrue(volumeTypeOption.get().deleteVolumeType(id));
+            assertTrue(volumeTypeOption.get().delete(id));
             assertTrue(new RetryablePredicate<VolumeTypeApi>(new Predicate<VolumeTypeApi>() {
                @Override
                public boolean apply(VolumeTypeApi volumeApi) {
-                  return volumeApi.getVolumeType(id) == null;
+                  return volumeApi.get(id) == null;
                }
             }, 5 * 1000L).apply(volumeTypeOption.get()));
          }
       }
-      super.tearDown();
+      super.tearDownContext();
    }
 
    public void testCreateVolumeType() {
       if (volumeTypeOption.isPresent()) {
-         testVolumeType = volumeTypeOption.get().createVolumeType(
+         testVolumeType = volumeTypeOption.get().create(
                "jclouds-test-1", CreateVolumeTypeOptions.Builder.specs(ImmutableMap.of("test", "value1")));
          assertTrue(new RetryablePredicate<VolumeTypeApi>(new Predicate<VolumeTypeApi>() {
             @Override
             public boolean apply(VolumeTypeApi volumeTypeApi) {
-               return volumeTypeApi.getVolumeType(testVolumeType.getId()) != null;
+               return volumeTypeApi.get(testVolumeType.getId()) != null;
             }
          }, 180 * 1000L).apply(volumeTypeOption.get()));
 
-         assertEquals(volumeTypeOption.get().getVolumeType(testVolumeType.getId()).getName(), "jclouds-test-1");
-         assertEquals(volumeTypeOption.get().getVolumeType(testVolumeType.getId()).getExtraSpecs(), ImmutableMap.of("test", "value1"));
+         assertEquals(volumeTypeOption.get().get(testVolumeType.getId()).getName(), "jclouds-test-1");
+         assertEquals(volumeTypeOption.get().get(testVolumeType.getId()).getExtraSpecs(), ImmutableMap.of("test", "value1"));
       }
    }
 
    @Test(dependsOnMethods = "testCreateVolumeType")
    public void testListVolumeTypes() {
       if (volumeTypeOption.isPresent()) {
-         Set<? extends VolumeType> volumeTypes = volumeTypeOption.get().listVolumeTypes();
+         Set<? extends VolumeType> volumeTypes = volumeTypeOption.get().list().toImmutableSet();
          assertNotNull(volumeTypes);
          boolean foundIt = false;
          for (VolumeType vt : volumeTypes) {
-            VolumeType details = volumeTypeOption.get().getVolumeType(vt.getId());
+            VolumeType details = volumeTypeOption.get().get(vt.getId());
             assertNotNull(details);
             if (Objects.equal(details.getId(), testVolumeType.getId())) {
                foundIt = true;
             }
          }
-         assertTrue(foundIt, "Failed to find the volume type we created in listVolumeTypes() response");
+         assertTrue(foundIt, "Failed to find the volume type we created in list() response");
       }
    }
 
    @Test(dependsOnMethods = "testCreateVolumeType")
    public void testExtraSpecs() {
       if (volumeTypeOption.isPresent()) {
-         assertEquals(volumeTypeOption.get().getAllExtraSpecs(testVolumeType.getId()), ImmutableMap.of("test", "value1"));
+         assertEquals(volumeTypeOption.get().getExtraSpecs(testVolumeType.getId()), ImmutableMap.of("test", "value1"));
          assertEquals(volumeTypeOption.get().getExtraSpec(testVolumeType.getId(), "test"),  "value1");
-         assertTrue(volumeTypeOption.get().setAllExtraSpecs(testVolumeType.getId(), ImmutableMap.of("test1", "wibble")));
+         assertTrue(volumeTypeOption.get().updateExtraSpecs(testVolumeType.getId(), ImmutableMap.of("test1", "wibble")));
       }
    }
 
    @Test(dependsOnMethods = "testCreateVolumeType")
    public void testUpdateIndividualSpec() {
       if (volumeTypeOption.isPresent()) {
-         assertTrue(volumeTypeOption.get().setExtraSpec(testVolumeType.getId(), "test1", "freddy"));
+         assertTrue(volumeTypeOption.get().updateExtraSpec(testVolumeType.getId(), "test1", "freddy"));
          assertEquals(volumeTypeOption.get().getExtraSpec(testVolumeType.getId(), "test1"), "freddy");
       }
    }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ExtensionApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ExtensionApiExpectTest.java
index 12fa23a..c4d6453 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ExtensionApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ExtensionApiExpectTest.java
@@ -56,7 +56,7 @@
 
       assertEquals(apiWhenExtensionsExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExtensionsExist.getExtensionApiForZone("az-1.region-a.geo-1").listExtensions().toString(),
+      assertEquals(apiWhenExtensionsExist.getExtensionApiForZone("az-1.region-a.geo-1").list().toString(),
             new ParseExtensionListTest().expected().toString());
    }
 
@@ -73,7 +73,7 @@
       NovaApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, listExtensions, listExtensionsResponse);
 
-      assertTrue(apiWhenNoServersExist.getExtensionApiForZone("az-1.region-a.geo-1").listExtensions().isEmpty());
+      assertTrue(apiWhenNoServersExist.getExtensionApiForZone("az-1.region-a.geo-1").list().isEmpty());
    }
 
    // TODO: gson deserializer for Multimap
@@ -92,7 +92,7 @@
       NovaApi apiWhenExtensionsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, getExtension, getExtensionResponse);
 
-      assertEquals(apiWhenExtensionsExist.getExtensionApiForZone("az-1.region-a.geo-1").getExtensionByAlias("RS-PIE")
+      assertEquals(apiWhenExtensionsExist.getExtensionApiForZone("az-1.region-a.geo-1").get("RS-PIE")
             .toString(), new ParseExtensionTest().expected().toString());
    }
 
@@ -110,7 +110,7 @@
       NovaApi apiWhenNoExtensionsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, getExtension, getExtensionResponse);
 
-      assertNull(apiWhenNoExtensionsExist.getExtensionApiForZone("az-1.region-a.geo-1").getExtensionByAlias("RS-PIE"));
+      assertNull(apiWhenNoExtensionsExist.getExtensionApiForZone("az-1.region-a.geo-1").get("RS-PIE"));
 
    }
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ExtensionApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ExtensionApiLiveTest.java
index 9a6d3e9..2f1ef50 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ExtensionApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ExtensionApiLiveTest.java
@@ -46,7 +46,7 @@
     public void testListExtensions() throws Exception {
        for (String zoneId : zones) {
           ExtensionApi api = novaContext.getApi().getExtensionApiForZone(zoneId);
-          Set<? extends Extension> response = api.listExtensions();
+          Set<? extends Extension> response = api.list();
           assertNotNull(response);
           assertFalse(response.isEmpty());
            for (Extension extension : response) {
@@ -69,9 +69,9 @@
     public void testGetExtensionByAlias() throws Exception {
        for (String zoneId : zones) {
            ExtensionApi api = novaContext.getApi().getExtensionApiForZone(zoneId);
-           Set<? extends Extension> response = api.listExtensions();
+           Set<? extends Extension> response = api.list();
            for (Extension extension : response) {
-              Extension details = api.getExtensionByAlias(extension.getId());
+              Extension details = api.get(extension.getId());
               assertNotNull(details);
               assertEquals(details.getId(), extension.getId());
               assertEquals(details.getName(), extension.getName());
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiExpectTest.java
index 8f2b73c..8b05f8c 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiExpectTest.java
@@ -56,7 +56,7 @@
 
       assertEquals(apiWhenFlavorsExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenFlavorsExist.getFlavorApiForZone("az-1.region-a.geo-1").listFlavors().toString(),
+      assertEquals(apiWhenFlavorsExist.getFlavorApiForZone("az-1.region-a.geo-1").list().concat().toString(),
             new ParseFlavorListTest().expected().toString());
    }
 
@@ -73,7 +73,7 @@
       NovaApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, listFlavors, listFlavorsResponse);
 
-      assertTrue(apiWhenNoServersExist.getFlavorApiForZone("az-1.region-a.geo-1").listFlavors().isEmpty());
+      assertTrue(apiWhenNoServersExist.getFlavorApiForZone("az-1.region-a.geo-1").list().concat().isEmpty());
    }
 
    // TODO: gson deserializer for Multimap
@@ -93,7 +93,7 @@
             responseWithKeystoneAccess, getFlavor, getFlavorResponse);
 
       assertEquals(
-            apiWhenFlavorsExist.getFlavorApiForZone("az-1.region-a.geo-1").getFlavor("52415800-8b69-11e0-9b19-734f1195ff37")
+            apiWhenFlavorsExist.getFlavorApiForZone("az-1.region-a.geo-1").get("52415800-8b69-11e0-9b19-734f1195ff37")
                   .toString(), new ParseFlavorTest().expected().toString());
    }
 
@@ -111,7 +111,7 @@
       NovaApi apiWhenNoFlavorsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, getFlavor, getFlavorResponse);
 
-      assertNull(apiWhenNoFlavorsExist.getFlavorApiForZone("az-1.region-a.geo-1").getFlavor("123"));
+      assertNull(apiWhenNoFlavorsExist.getFlavorApiForZone("az-1.region-a.geo-1").get("123"));
 
    }
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiLiveTest.java
index 6dbdb99..a45e6bf 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/FlavorApiLiveTest.java
@@ -47,7 +47,7 @@
    public void testListFlavors() throws Exception {
       for (String zoneId : zones) {
          FlavorApi api = novaContext.getApi().getFlavorApiForZone(zoneId);
-         Set<? extends Resource> response = api.listFlavors();
+         Set<? extends Resource> response = api.list().concat().toImmutableSet();
          assertNotNull(response);
          assertFalse(response.isEmpty());
          for (Resource flavor : response) {
@@ -67,7 +67,7 @@
    public void testListFlavorsInDetail() throws Exception {
       for (String zoneId : zones) {
          FlavorApi api = novaContext.getApi().getFlavorApiForZone(zoneId);
-         Set<? extends Flavor> response = api.listFlavorsInDetail();
+         Set<? extends Flavor> response = api.listInDetail().concat().toImmutableSet();
          assertNotNull(response);
          assertFalse(response.isEmpty());
          for (Flavor flavor : response) {
@@ -90,9 +90,9 @@
    public void testGetFlavorById() throws Exception {
       for (String zoneId : zones) {
          FlavorApi api = novaContext.getApi().getFlavorApiForZone(zoneId);
-         Set<? extends Flavor> response = api.listFlavorsInDetail();
+         Set<? extends Flavor> response = api.listInDetail().concat().toImmutableSet();
          for (Flavor flavor : response) {
-            Flavor details = api.getFlavor(flavor.getId());
+            Flavor details = api.get(flavor.getId());
             assertNotNull(details);
             assertEquals(details.getId(), flavor.getId());
             assertEquals(details.getName(), flavor.getName());
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ImageApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ImageApiExpectTest.java
index 2b3768b..81b8403 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ImageApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ImageApiExpectTest.java
@@ -21,6 +21,7 @@
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
@@ -28,8 +29,11 @@
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
 import org.jclouds.openstack.nova.v2_0.parse.ParseImageListTest;
 import org.jclouds.openstack.nova.v2_0.parse.ParseImageTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseMetadataListTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseMetadataUpdateTest;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -40,39 +44,39 @@
 @Test(groups = "unit", testName = "ImageAsyncApiTest")
 public class ImageApiExpectTest extends BaseNovaApiExpectTest {
    public void testListImagesWhenResponseIs2xx() throws Exception {
-      HttpRequest listImages = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listImagesResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/image_list.json")).build();
 
       NovaApi apiWhenImagesExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, listImages, listImagesResponse);
+            responseWithKeystoneAccess, list, listResponse);
 
       assertEquals(apiWhenImagesExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenImagesExist.getImageApiForZone("az-1.region-a.geo-1").listImages().toString(),
+      assertEquals(apiWhenImagesExist.getImageApiForZone("az-1.region-a.geo-1").list().concat().toString(),
             new ParseImageListTest().expected().toString());
    }
 
    public void testListImagesWhenReponseIs404IsEmpty() throws Exception {
-      HttpRequest listImages = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listImagesResponse = HttpResponse.builder().statusCode(404).build();
+      HttpResponse listResponse = HttpResponse.builder().statusCode(404).build();
 
       NovaApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-            responseWithKeystoneAccess, listImages, listImagesResponse);
+            responseWithKeystoneAccess, list, listResponse);
 
-      assertTrue(apiWhenNoServersExist.getImageApiForZone("az-1.region-a.geo-1").listImages().isEmpty());
+      assertTrue(apiWhenNoServersExist.getImageApiForZone("az-1.region-a.geo-1").list().concat().isEmpty());
    }
 
    public void testGetImageWhenResponseIs2xx() throws Exception {
@@ -91,7 +95,7 @@
             responseWithKeystoneAccess, getImage, getImageResponse);
 
       assertEquals(
-            apiWhenImagesExist.getImageApiForZone("az-1.region-a.geo-1").getImage("52415800-8b69-11e0-9b19-734f5736d2a2")
+            apiWhenImagesExist.getImageApiForZone("az-1.region-a.geo-1").get("52415800-8b69-11e0-9b19-734f5736d2a2")
                   .toString(), new ParseImageTest().expected().toString());
    }
 
@@ -108,9 +112,268 @@
       NovaApi apiWhenNoImagesExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, getImage, getImageResponse);
 
-      assertNull(apiWhenNoImagesExist.getImageApiForZone("az-1.region-a.geo-1").getImage(
+      assertNull(apiWhenNoImagesExist.getImageApiForZone("az-1.region-a.geo-1").get(
             "52415800-8b69-11e0-9b19-734f5736d2a2"));
 
    }
 
+   public void testListMetadataWhenResponseIs2xx() throws Exception {
+	      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      HttpRequest getMetadata = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken).build();
+        
+      HttpResponse getMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/metadata_list.json")).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, getMetadata, getMetadataResponse);
+
+      assertEquals(apiWhenServerExists.getImageApiForZone("az-1.region-a.geo-1").getMetadata(imageId).toString(),  
+             new ParseMetadataListTest().expected().toString());
+   }
+   
+   public void testListMetadataWhenResponseIs404() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      HttpRequest getMetadata = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata")
+            .addHeader("Accept", "*/*")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse getMetadataResponse = HttpResponse.builder().statusCode(404).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, getMetadata, getMetadataResponse);
+
+      try {
+         apiWhenServerExists.getImageApiForZone("az-1.region-a.geo-1").getMetadata(imageId);
+         fail("Expected an exception.");
+         } catch (Exception e) {
+            ;
+         }
+   }
+
+   public void testSetMetadataWhenResponseIs2xx() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 1")
+              .put("Image Version", "2.1")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("PUT")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 1\",\"Image Version\":\"2.1\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/metadata_list.json")).build();
+      
+      NovaApi apiWhenImageExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      assertEquals(apiWhenImageExists.getImageApiForZone("az-1.region-a.geo-1").setMetadata(imageId, metadata).toString(),  
+             new ParseMetadataListTest().expected().toString());
+   }
+
+   public void testSetMetadataWhenResponseIs404() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 1")
+              .put("Image Version", "2.1")
+              .build();
+      
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("PUT")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" +imageId + "/metadata")
+            .addHeader("Accept", "*/*")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 1\",\"Image Version\":\"2.1\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(404).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      try {
+    	 apiWhenServerExists.getImageApiForZone("az-1.region-a.geo-1").setMetadata(imageId, metadata);
+         fail("Expected an exception.");
+      } catch (Exception e) {
+         ;
+      }
+   }
+
+   public void testUpdateMetadataWhenResponseIs2xx() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 2")
+              .put("Server Description", "Simple Server")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("POST")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 2\",\"Server Description\":\"Simple Server\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/metadata_updated.json")).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      assertEquals(apiWhenServerExists.getImageApiForZone("az-1.region-a.geo-1").updateMetadata(imageId, metadata).toString(),  
+             new ParseMetadataUpdateTest().expected().toString());
+   }
+
+   public void testUpdateMetadataWhenResponseIs404() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 2")
+              .put("Server Description", "Simple Server")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("POST")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + imageId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 2\",\"Server Description\":\"Simple Server\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(404)
+              .payload(payloadFromResource("/metadata_updated.json")).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      try {
+    	 apiWhenServerExists.getImageApiForZone("az-1.region-a.geo-1").setMetadata(imageId, metadata);
+         fail("Expected an exception.");
+      } catch (Exception e) {
+         ;
+      }
+   }
+
+   public void testGetMetadataItemWhenResponseIs2xx() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      String key = "Image%20Version";
+
+      HttpRequest getMetadata = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata/" + key)
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse getMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromString("{\"metadata\":{\"Image Version\":\"2.5\"}}")).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, getMetadata, getMetadataResponse);
+
+      assertEquals(apiWhenServerExists.getImageApiForZone("az-1.region-a.geo-1").getMetadata(imageId, "Image Version").toString(),  
+             "2.5");
+   }
+
+   public void testGetMetadataItemWhenResponseIs404() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      String key = "Image%20Version";
+
+      HttpRequest getMetadata = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata/" + key)
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse getMetadataResponse = HttpResponse.builder().statusCode(404)
+              .payload(payloadFromStringWithContentType("{\"metadata\":{\"Image Version\":\"2.5\"}}", "application/json")).build();
+
+      NovaApi apiWhenImageExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, getMetadata, getMetadataResponse);
+
+      assertNull(apiWhenImageExists.getImageApiForZone("az-1.region-a.geo-1").getMetadata(imageId, key));
+   }
+
+   public void testSetMetadataItemWhenResponseIs2xx() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      String key = "Image Version";
+
+      HttpRequest updateMetadata = HttpRequest
+            .builder()
+            .method("PUT")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata/" + "Image%20Version")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Image Version\":\"2.5\"}}", "application/json"))
+            .build();
+
+      HttpResponse updateMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromStringWithContentType("{\"metadata\":{\"Image Version\":\"2.5\"}}", "application/json")).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, updateMetadata, updateMetadataResponse);
+      
+      assertEquals(apiWhenServerExists.getImageApiForZone("az-1.region-a.geo-1").updateMetadata(imageId, key, "2.5").toString(),  
+             "2.5");
+   }
+
+   public void testDeleteMetadataItemWhenResponseIs2xx() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      String key = "Image%20Version";
+      
+      HttpRequest deleteMetadata = HttpRequest
+            .builder()
+            .method("DELETE")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata/" + key)
+            .addHeader("Accept", "*/*")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse deleteMetadataResponse = HttpResponse.builder().statusCode(204).build();
+      
+      NovaApi apiWhenImageExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, deleteMetadata, deleteMetadataResponse);
+
+      apiWhenImageExists.getImageApiForZone("az-1.region-a.geo-1").deleteMetadata(imageId, key);
+   }
+
+   public void testDeleteMetadataItemWhenResponseIs404() throws Exception {
+      String imageId = "52415800-8b69-11e0-9b19-734f5736d2a2";
+      String key = "Image%20Version";
+
+      HttpRequest deleteMetadata = HttpRequest
+            .builder()
+            .method("DELETE")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/" + imageId + "/metadata/" + key)
+            .addHeader("Accept", "*/*")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse deleteMetadataResponse = HttpResponse.builder().statusCode(404).build();
+
+      NovaApi apiWhenImageExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, deleteMetadata, deleteMetadataResponse);
+
+      apiWhenImageExists.getImageApiForZone("az-1.region-a.geo-1").deleteMetadata(imageId, key);
+
+   }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ImageApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ImageApiLiveTest.java
index 7f9bc2b..678115a 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ImageApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ImageApiLiveTest.java
@@ -42,7 +42,7 @@
    public void testListImages() throws Exception {
       for (String zoneId : zones) {
          ImageApi api = novaContext.getApi().getImageApiForZone(zoneId);
-         Set<? extends Resource> response = api.listImages();
+         Set<? extends Resource> response = api.list().concat().toImmutableSet();
          assertNotNull(response);
          assertFalse(response.isEmpty());
          for (Resource image : response) {
@@ -57,7 +57,7 @@
    public void testListImagesInDetail() throws Exception {
       for (String zoneId : novaContext.getApi().getConfiguredZones()) {
          ImageApi api = novaContext.getApi().getImageApiForZone(zoneId);
-         Set<? extends Image> response = api.listImagesInDetail();
+         Set<? extends Image> response = api.listInDetail().concat().toImmutableSet();
          assertNotNull(response);
          assertFalse(response.isEmpty());
          for (Image image : response) {
@@ -65,14 +65,14 @@
             assertNotNull(image.getName());
             assertNotNull(image.getLinks());
             assertNotNull(image.getCreated());
-            assertTrue(image.getMinDisk() > 0);
-            assertTrue(image.getMinRam() > 0);
+            // image.getMinDisk() can be zero
+            // image.getMinRam() can be zero
             assertTrue(image.getProgress() >= 0 && image.getProgress() <= 100);
             assertNotNull(image.getStatus());
-            assertNotNull(image.getServer());
-            assertNotNull(image.getTenantId());
-            assertNotNull(image.getUpdated());
-            assertNotNull(image.getUserId());
+            // image.getServer() can be null
+            // image.getTenantId() can be null
+            // image.getUpdated() can be null
+            // image.getUserId() can be null
          }
       }
    }
@@ -81,9 +81,9 @@
    public void testGetImageById() throws Exception {
       for (String zoneId : novaContext.getApi().getConfiguredZones()) {
          ImageApi api = novaContext.getApi().getImageApiForZone(zoneId);
-         Set<? extends Image> response = api.listImagesInDetail();
+         Set<? extends Image> response = api.listInDetail().concat().toImmutableSet();
          for (Image image : response) {
-            Image details = api.getImage(image.getId());
+            Image details = api.get(image.getId());
             assertNotNull(details);
             assertEquals(details.getId(), image.getId());
             assertEquals(details.getName(), image.getName());
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiExpectTest.java
index 897ee01..dde2002 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiExpectTest.java
@@ -28,9 +28,12 @@
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiExpectTest;
 import org.jclouds.openstack.nova.v2_0.options.CreateServerOptions;
 import org.jclouds.openstack.nova.v2_0.parse.ParseCreatedServerTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseMetadataListTest;
+import org.jclouds.openstack.nova.v2_0.parse.ParseMetadataUpdateTest;
 import org.jclouds.openstack.nova.v2_0.parse.ParseServerListTest;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.ImmutableSet;
 
@@ -58,7 +61,7 @@
 
       assertEquals(apiWhenServersExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").listServers().toString(),
+      assertEquals(apiWhenServersExist.getServerApiForZone("az-1.region-a.geo-1").list().concat().toString(),
             new ParseServerListTest().expected().toString());
    }
 
@@ -75,7 +78,7 @@
       NovaApi apiWhenNoServersExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, listServers, listServersResponse);
 
-      assertTrue(apiWhenNoServersExist.getServerApiForZone("az-1.region-a.geo-1").listServers().isEmpty());
+      assertTrue(apiWhenNoServersExist.getServerApiForZone("az-1.region-a.geo-1").list().concat().isEmpty());
    }
 
    public void testCreateServerWhenResponseIs202() throws Exception {
@@ -96,7 +99,7 @@
       NovaApi apiWithNewServer = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, createServer, createServerResponse);
 
-      assertEquals(apiWithNewServer.getServerApiForZone("az-1.region-a.geo-1").createServer("test-e92", "1241", "100").toString(),
+      assertEquals(apiWithNewServer.getServerApiForZone("az-1.region-a.geo-1").create("test-e92", "1241", "100").toString(),
               new ParseCreatedServerTest().expected().toString());
    }
 
@@ -120,7 +123,7 @@
       NovaApi apiWithNewServer = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
             responseWithKeystoneAccess, createServer, createServerResponse);
 
-      assertEquals(apiWithNewServer.getServerApiForZone("az-1.region-a.geo-1").createServer("test-e92", "1241",
+      assertEquals(apiWithNewServer.getServerApiForZone("az-1.region-a.geo-1").create("test-e92", "1241",
                "100", new CreateServerOptions().securityGroupNames("group1", "group2")).toString(),
               new ParseCreatedServerTest().expected().toString());
    }
@@ -196,7 +199,7 @@
       NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
                responseWithKeystoneAccess, stopServer, stopServerResponse);
 
-      apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").stopServer(serverId);
+      apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").stop(serverId);
    }
    
    public void testStopServerWhenResponseIs404() throws Exception {
@@ -218,7 +221,7 @@
                responseWithKeystoneAccess, stopServer, stopServerResponse);
 
       try {
-         apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").stopServer(serverId);
+         apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").stop(serverId);
          fail("Expected an exception.");
       } catch (Exception e) {
          ;
@@ -243,7 +246,7 @@
       NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
                responseWithKeystoneAccess, startServer, startServerResponse);
 
-      apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").startServer(serverId);
+      apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").start(serverId);
    }
    
    public void testStartServerWhenResponseIs404() throws Exception {
@@ -264,11 +267,314 @@
                responseWithKeystoneAccess, startServer, startServerResponse);
 
       try {
-         apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").startServer(serverId);
+         apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").start(serverId);
          fail("Expected an exception.");
       } catch (Exception e) {
          ;
       }
    }
 
+   public void testListMetadataWhenResponseIs2xx() throws Exception {
+      String serverId = "123";
+      
+      HttpRequest getMetadata = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken).build();
+        
+      HttpResponse getMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/metadata_list.json")).build();
+      
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, getMetadata, getMetadataResponse);
+
+      assertEquals(apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").getMetadata(serverId).toString(),  
+             new ParseMetadataListTest().expected().toString());
+   }
+   
+   public void testListMetadataWhenResponseIs404() throws Exception {
+      String serverId = "123";
+      HttpRequest getMetadata = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "*/*")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse getMetadataResponse = HttpResponse.builder().statusCode(404).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, getMetadata, getMetadataResponse);
+
+      try {
+    	 apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").getMetadata(serverId);
+         fail("Expected an exception.");
+      } catch (Exception e) {
+         ;
+      }
+   }
+
+   public void testSetMetadataWhenResponseIs2xx() throws Exception {
+      String serverId = "123";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 1")
+              .put("Image Version", "2.1")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("PUT")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 1\",\"Image Version\":\"2.1\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/metadata_list.json")).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      assertEquals(apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").setMetadata(serverId, metadata).toString(),  
+             new ParseMetadataListTest().expected().toString());
+   }
+
+   public void testSetMetadataWhenResponseIs404() throws Exception {
+      String serverId = "123";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 1")
+              .put("Image Version", "2.1")
+              .build();
+      
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("PUT")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "*/*")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 1\",\"Image Version\":\"2.1\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(404).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      try {
+    	 apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").setMetadata(serverId, metadata);
+         fail("Expected an exception.");
+      } catch (Exception e) {
+         ;
+      }
+   }
+
+   public void testUpdateMetadataWhenResponseIs2xx() throws Exception {
+      String serverId = "123";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 2")
+              .put("Server Description", "Simple Server")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("POST")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 2\",\"Server Description\":\"Simple Server\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/metadata_updated.json")).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      assertEquals(apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").updateMetadata(serverId, metadata).toString(),  
+             new ParseMetadataUpdateTest().expected().toString());
+   }
+
+   public void testUpdateMetadataWhenResponseIs404() throws Exception {
+      String serverId = "123";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 2")
+              .put("Server Description", "Simple Server")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("POST")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 2\",\"Server Description\":\"Simple Server\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(404)
+              .payload(payloadFromResource("/metadata_updated.json")).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      try {
+    	 apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").setMetadata(serverId, metadata);
+         fail("Expected an exception.");
+      } catch (Exception e) {
+         ;
+      }
+   }
+
+   public void testGetMetadataItemWhenResponseIs2xx() throws Exception {
+      String serverId = "123";
+      String key = "Server Label";
+
+      HttpRequest getMetadata = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata/" + "Server%20Label")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse getMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/metadata_item.json")).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, getMetadata, getMetadataResponse);
+
+      assertEquals(apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").getMetadata(serverId, key).toString(),  
+             "Web Head 1");
+   }
+
+   public void testGetMetadataItemWhenResponseIs404() throws Exception {
+      String serverId = "123";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 1")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 2\",\"Server Description\":\"Simple Server\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(404)
+              .payload(payloadFromResource("/metadata_updated.json")).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      try {
+    	 apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").setMetadata(serverId, metadata);
+         fail("Expected an exception.");
+      } catch (Exception e) {
+         ;
+      }
+   }
+
+   public void testSetMetadataItemWhenResponseIs2xx() throws Exception {
+      String serverId = "123";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 2")
+              .put("Server Description", "Simple Server")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("POST")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 2\",\"Server Description\":\"Simple Server\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/metadata_updated.json")).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      assertEquals(apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").updateMetadata(serverId, metadata).toString(),  
+             new ParseMetadataUpdateTest().expected().toString());
+   }
+
+   public void testSetMetadataItemWhenResponseIs404() throws Exception {
+      String serverId = "123";
+      ImmutableMap<String, String> metadata = new ImmutableMap.Builder<String, String>()
+              .put("Server Label", "Web Head 2")
+              .put("Server Description", "Simple Server")
+              .build();
+
+      HttpRequest setMetadata = HttpRequest
+            .builder()
+            .method("POST")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken)
+            .payload(payloadFromStringWithContentType("{\"metadata\":{\"Server Label\":\"Web Head 2\",\"Server Description\":\"Simple Server\"}}","application/json"))
+            .build();
+
+      HttpResponse setMetadataResponse = HttpResponse.builder().statusCode(404)
+              .payload(payloadFromResource("/metadata_updated.json")).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, setMetadata, setMetadataResponse);
+
+      try {
+    	 apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").setMetadata(serverId, metadata);
+         fail("Expected an exception.");
+      } catch (Exception e) {
+         ;
+      }
+   }
+
+   public void testDeleteMetadataItemWhenResponseIs2xx() throws Exception {
+      String serverId = "123";
+      String key = "Server%20Label";
+
+      HttpRequest updateMetadata = HttpRequest
+            .builder()
+            .method("DELETE")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata/" + key)
+            .addHeader("Accept", "*/*")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse updateMetadataResponse = HttpResponse.builder().statusCode(204).build();
+      
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, updateMetadata, updateMetadataResponse);
+
+      apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").deleteMetadata(serverId, key);
+
+   }
+
+   public void testDeleteMetadataItemWhenResponseIs404() throws Exception {
+      String serverId = "123";
+      String key = "Server%20Label";
+
+      HttpRequest deleteMetadata = HttpRequest
+            .builder()
+            .method("DELETE")
+            .endpoint("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/servers/" + serverId + "/metadata/" + key)
+            .addHeader("Accept", "*/*")
+            .addHeader("X-Auth-Token", authToken)
+            .build();
+
+      HttpResponse deleteMetadataResponse = HttpResponse.builder().statusCode(404).build();
+
+      NovaApi apiWhenServerExists = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
+               responseWithKeystoneAccess, deleteMetadata, deleteMetadataResponse);
+
+      apiWhenServerExists.getServerApiForZone("az-1.region-a.geo-1").deleteMetadata(serverId, key);
+
+   }
 }
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiLiveTest.java
index b8d78ed..e02dc43 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/features/ServerApiLiveTest.java
@@ -19,9 +19,9 @@
 package org.jclouds.openstack.nova.v2_0.features;
 
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.*;
-
-import java.util.Set;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
 
 import org.jclouds.openstack.nova.v2_0.domain.Server;
 import org.jclouds.openstack.nova.v2_0.internal.BaseNovaApiLiveTest;
@@ -44,12 +44,7 @@
     public void testListServers() throws Exception {
        for (String zoneId : zones) {
           ServerApi api = novaContext.getApi().getServerApiForZone(zoneId);
-          Set<? extends Resource> response = api.listServers();
-          assertNotNull(response);
-          assertFalse(response.isEmpty());
-          assert null != response;
-          assertTrue(response.size() >= 0);
-          for (Resource server : response) {
+          for (Resource server : api.list().concat()) {
              checkResource(server);
           }
        }
@@ -59,10 +54,7 @@
     public void testListServersInDetail() throws Exception {
        for (String zoneId : zones) {
           ServerApi api = novaContext.getApi().getServerApiForZone(zoneId);
-          Set<? extends Server> response = api.listServersInDetail();
-          assertNotNull(response);
-          assertFalse(response.isEmpty());
-          for (Server server : response) {
+          for (Server server : api.listInDetail().concat()) {
              checkServer(server);
           }
        }
@@ -72,9 +64,8 @@
     public void testGetServerById() throws Exception {
        for (String zoneId : zones) {
           ServerApi api = novaContext.getApi().getServerApiForZone(zoneId);
-          Set<? extends Resource> response = api.listServers();
-          for (Resource server : response) {
-             Server details = api.getServer(server.getId());
+          for (Resource server : api.list().concat()) {
+             Server details = api.get(server.getId());
              assertEquals(details.getId(), server.getId());
              assertEquals(details.getName(), server.getName());
              assertEquals(details.getLinks(), server.getLinks());
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/functions/CreateSecurityGroupIfNeededTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/functions/CreateSecurityGroupIfNeededTest.java
index 4965d2c..4c38df0 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/functions/CreateSecurityGroupIfNeededTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/functions/CreateSecurityGroupIfNeededTest.java
@@ -44,7 +44,7 @@
  */
 @Test(groups = "unit", testName = "CreateSecurityGroupIfNeededTest")
 public class CreateSecurityGroupIfNeededTest extends BaseNovaApiExpectTest {
-   HttpRequest createSecurityGroup = HttpRequest.builder().method("POST").endpoint(
+   HttpRequest create = HttpRequest.builder().method("POST").endpoint(
             URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers(
             ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                      authToken).build())
@@ -61,13 +61,13 @@
       builder.put(extensionsOfNovaRequest, extensionsOfNovaResponse);
       int groupId = 2769;
 
-      HttpResponse createSecurityGroupResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse createResponse = HttpResponse.builder().statusCode(200)
                .payload(
                         payloadFromStringWithContentType(
                                  String.format("{\"security_group\": {\"rules\": [], \"tenant_id\": \"37936628937291\", \"id\": %s, \"name\": \"jclouds_mygroup\", \"description\": \"jclouds_mygroup\"}}", groupId),
                                  "application/json; charset=UTF-8")).build();
 
-      builder.put(createSecurityGroup, createSecurityGroupResponse);
+      builder.put(create, createResponse);
       
       int ruleId = 10331;
       
@@ -138,23 +138,23 @@
       builder.put(keystoneAuthWithUsernameAndPasswordAndTenantName, responseWithKeystoneAccess);
       builder.put(extensionsOfNovaRequest, extensionsOfNovaResponse);
 
-      HttpResponse createSecurityGroupResponse = HttpResponse.builder().statusCode(400)
+      HttpResponse createResponse = HttpResponse.builder().statusCode(400)
                .payload(
                         payloadFromStringWithContentType(
                                  "{\"badRequest\": {\"message\": \"Security group test already exists\", \"code\": 400}}",
                                  "application/json; charset=UTF-8")).build();
 
-      builder.put(createSecurityGroup, createSecurityGroupResponse);
+      builder.put(create, createResponse);
           
-      HttpRequest listSecurityGroups = HttpRequest.builder().method("GET").endpoint(
+      HttpRequest list = HttpRequest.builder().method("GET").endpoint(
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers(
                ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                         authToken).build()).build();
 
-      HttpResponse listSecurityGroupsResponse = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/securitygroup_list_details_computeservice_typical.json")).build();
 
-      builder.put(listSecurityGroups, listSecurityGroupsResponse);
+      builder.put(list, listResponse);
 
       NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(builder.build());
 
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/functions/FindSecurityGroupWithNameAndReturnTrueExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/functions/FindSecurityGroupWithNameAndReturnTrueExpectTest.java
index e386bf4..8bdba65 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/functions/FindSecurityGroupWithNameAndReturnTrueExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/functions/FindSecurityGroupWithNameAndReturnTrueExpectTest.java
@@ -46,17 +46,17 @@
 public class FindSecurityGroupWithNameAndReturnTrueExpectTest extends BaseNovaApiExpectTest {
 
    public void testUpdateReferenceWhenSecurityGroupListContainsGroupName() throws Exception {
-      HttpRequest listSecurityGroups = HttpRequest.builder().method("GET").endpoint(
+      HttpRequest list = HttpRequest.builder().method("GET").endpoint(
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers(
                ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                         authToken).build()).build();
 
-      HttpResponse listSecurityGroupsResponse = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/securitygroup_list.json")).build();
 
       NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listSecurityGroups,
-               listSecurityGroupsResponse);
+               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list,
+               listResponse);
 
       FindSecurityGroupWithNameAndReturnTrue predicate = new FindSecurityGroupWithNameAndReturnTrue(
                apiWhenSecurityGroupsExist);
@@ -74,17 +74,17 @@
    }
 
    public void testDoesNotUpdateReferenceWhenSecurityGroupListMissingGroupName() throws Exception {
-      HttpRequest listSecurityGroups = HttpRequest.builder().method("GET").endpoint(
+      HttpRequest list = HttpRequest.builder().method("GET").endpoint(
                URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/os-security-groups")).headers(
                ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                         authToken).build()).build();
 
-      HttpResponse listSecurityGroupsResponse = HttpResponse.builder().statusCode(200).payload(
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200).payload(
                payloadFromResource("/securitygroup_list.json")).build();
 
       NovaApi apiWhenSecurityGroupsExist = requestsSendResponses(keystoneAuthWithUsernameAndPasswordAndTenantName,
-               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, listSecurityGroups,
-               listSecurityGroupsResponse);
+               responseWithKeystoneAccess, extensionsOfNovaRequest, extensionsOfNovaResponse, list,
+               listResponse);
 
       FindSecurityGroupWithNameAndReturnTrue predicate = new FindSecurityGroupWithNameAndReturnTrue(
                apiWhenSecurityGroupsExist);
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/internal/BaseNovaApiLiveTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/internal/BaseNovaApiLiveTest.java
index 2d90bd1..79bc69a 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/internal/BaseNovaApiLiveTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/internal/BaseNovaApiLiveTest.java
@@ -33,9 +33,9 @@
 import org.jclouds.openstack.nova.v2_0.features.FlavorApi;
 import org.jclouds.openstack.nova.v2_0.features.ImageApi;
 import org.jclouds.openstack.nova.v2_0.features.ServerApi;
+import org.jclouds.openstack.v2_0.domain.Resource;
 import org.jclouds.rest.RestContext;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Throwables;
@@ -50,6 +50,7 @@
  */
 @Test(groups = "live")
 public class BaseNovaApiLiveTest extends BaseComputeServiceContextLiveTest {
+   protected String hostName = System.getProperty("user.name").replace('.','-').toLowerCase();
 
    public BaseNovaApiLiveTest() {
       provider = "openstack-nova";
@@ -58,12 +59,19 @@
    protected Set<String> zones;
    protected RestContext<NovaApi, NovaAsyncApi> novaContext;
 
-   @BeforeGroups(groups = { "integration", "live" }, alwaysRun = true)
+   @BeforeClass(groups = { "integration", "live" })
    @Override
    public void setupContext() {
       super.setupContext();
       novaContext = view.unwrap();
       zones = novaContext.getApi().getConfiguredZones();
+      for (String zone : zones){
+         ServerApi api = novaContext.getApi().getServerApiForZone(zone);
+         for (Resource server : api.list().concat()){
+            if (server.getName().equals(hostName))
+               api.delete(server.getId());
+         }
+      }
    }
 
    @Override
@@ -74,17 +82,11 @@
       return props;
    }
    
-   @AfterGroups(groups = "live")
-   protected void tearDown() {
-      if (novaContext != null)
-         novaContext.close();
-   }
-   
    protected Server createServerInZone(String zoneId) {
       ServerApi serverApi = novaContext.getApi().getServerApiForZone(zoneId);
-      ServerCreated server = serverApi.createServer("test", imageIdForZone(zoneId), flavorRefForZone(zoneId));
+      ServerCreated server = serverApi.create(hostName, imageIdForZone(zoneId), flavorRefForZone(zoneId));
       blockUntilServerInState(server.getId(), serverApi, Status.ACTIVE);
-      return serverApi.getServer(server.getId());
+      return serverApi.get(server.getId());
    }
 
    /** 
@@ -93,10 +95,9 @@
     */
    protected void blockUntilServerInState(String serverId, ServerApi api, Status status) {
       Server currentDetails = null;
-      for (currentDetails = api.getServer(serverId); currentDetails.getStatus() != status ||
-           (currentDetails.getExtendedStatus().isPresent() && currentDetails.getExtendedStatus().get().getTaskState() != null);
-           currentDetails = api
-            .getServer(serverId)) {
+      for (currentDetails = api.get(serverId); currentDetails.getStatus() != status
+               || ((currentDetails.getExtendedStatus().isPresent() && currentDetails.getExtendedStatus().get()
+                        .getTaskState() != null)); currentDetails = api.get(serverId)) {
          System.out.printf("blocking on status %s%n%s%n", status, currentDetails);
          try {
             Thread.sleep(5 * 1000);
@@ -108,12 +109,12 @@
    
    protected String imageIdForZone(String zoneId) {
       ImageApi imageApi = novaContext.getApi().getImageApiForZone(zoneId);
-      return Iterables.getLast(imageApi.listImages()).getId();
+      return Iterables.getLast(imageApi.list().concat()).getId();
    }
 
    protected String flavorRefForZone(String zoneId) {
       FlavorApi flavorApi = novaContext.getApi().getFlavorApiForZone(zoneId);
-      return DEFAULT_FLAVOR_ORDERING.min(flavorApi.listFlavorsInDetail()).getId();
+      return DEFAULT_FLAVOR_ORDERING.min(flavorApi.listInDetail().concat()).getId();
    }
 
    static final Ordering<Flavor> DEFAULT_FLAVOR_ORDERING = new Ordering<Flavor>() {
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/internal/BaseNovaComputeServiceContextExpectTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/internal/BaseNovaComputeServiceContextExpectTest.java
index 7c56fb1..fdf5fae 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/internal/BaseNovaComputeServiceContextExpectTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/internal/BaseNovaComputeServiceContextExpectTest.java
@@ -39,12 +39,12 @@
 public abstract class BaseNovaComputeServiceContextExpectTest<T> extends BaseNovaExpectTest<T> implements
          Function<ComputeServiceContext, T> {
    
-   protected final HttpRequest listImagesDetail = HttpRequest.builder().method("GET").endpoint(
+   protected final HttpRequest listDetail = HttpRequest.builder().method("GET").endpoint(
             URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/3456/images/detail")).headers(
             ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
                      authToken).build()).build();
 
-   protected final HttpResponse listImagesDetailResponse = HttpResponse.builder().statusCode(200).payload(
+   protected final HttpResponse listDetailResponse = HttpResponse.builder().statusCode(200).payload(
             payloadFromResource("/image_list_detail.json")).build();
 
    protected final HttpRequest listFlavorsDetail = HttpRequest.builder().method("GET").endpoint(
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseKeyPairListTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseKeyPairListTest.java
index bc30d5b..3476998 100644
--- a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseKeyPairListTest.java
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseKeyPairListTest.java
@@ -18,9 +18,6 @@
  */
 package org.jclouds.openstack.nova.v2_0.parse;
 
-import java.util.Map;
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.core.MediaType;
 
@@ -28,11 +25,12 @@
 import org.jclouds.json.config.GsonModule;
 import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
 import org.jclouds.openstack.nova.v2_0.domain.KeyPair;
-import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.openstack.nova.v2_0.functions.internal.ParseKeyPairs;
+import org.jclouds.rest.annotations.ResponseParser;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 
@@ -41,7 +39,7 @@
  * @author Michael Arnold
  */
 @Test(groups = "unit", testName = "ParseKeyPairListTest")
-public class ParseKeyPairListTest extends BaseItemParserTest<Set<Map<String, KeyPair>>> {
+public class ParseKeyPairListTest extends BaseItemParserTest<FluentIterable<? extends KeyPair>> {
 
    @Override
    public String resource() {
@@ -49,26 +47,20 @@
    }
 
    @Override
-   @SelectJson("keypairs")
+   @ResponseParser(ParseKeyPairs.class)
    @Consumes(MediaType.APPLICATION_JSON)
-   public Set<Map<String, KeyPair>> expected() {
-      Map<String, KeyPair> kp1 = Maps.newHashMap();
-      kp1.put(
-            "keypair",
+   public FluentIterable<? extends KeyPair> expected() {
+      return FluentIterable.from(ImmutableSet.of(
             KeyPair
                   .builder()
                   .publicKey(
                         "ssh-rsa AAAXB3NzaC1yc2EAAAADAQABAAAAgQCy9EC3O7Ff80vPEfAHDQob61PGwcpYc5KE7tEZnZhrB9n0NyHPRm0E0M+ls3fcTa04HDi+R0DzmRwoyhHQJyI658v8kWZZcuvFjKCcsgsSh/dzdX0xTreLIzSOzt5U7RnZYfshP5cmxtF99yrEY3M/swdin0L+fXsTSkR1B42STQ== nova@nv-aw2az1-api0001")
-                  .name("default").fingerprint("ab:0c:f4:f3:54:c0:5d:3f:ed:62:ad:d3:94:7c:79:7c").build());
-      Map<String, KeyPair> kp2 = Maps.newHashMap();
-      kp2.put(
-            "keypair",
+                  .name("default").fingerprint("ab:0c:f4:f3:54:c0:5d:3f:ed:62:ad:d3:94:7c:79:7c").build(),
             KeyPair
                   .builder()
                   .publicKey(
                         "ssh-rsa AAAXB3NzaC1yc2EAAAADAQABAAAAgQDFNyGjgs6c9akgmZ2ou/fJf7Pdrc23hC95/gM/33OrG4GZABACE4DTioa/PGN+7rHv9YUavUCtXrWayhGniKq/wCuI5fo5TO4AmDNv7/sCGHIHFumADSIoLx0vFhGJIetXEWxL9r0lfFC7//6yZM2W3KcGjbMtlPXqBT9K9PzdyQ== nova@nv-aw2az1-api0001")
-                  .name("testkeypair").fingerprint("d2:1f:c9:2b:d8:90:77:5f:15:64:27:e3:9f:77:1d:e4").build());
-      return ImmutableSet.of(kp1, kp2);
+                  .name("testkeypair").fingerprint("d2:1f:c9:2b:d8:90:77:5f:15:64:27:e3:9f:77:1d:e4").build()));
    }
 
    protected Injector injector() {
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataItemTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataItemTest.java
new file mode 100644
index 0000000..d99709a
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataItemTest.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.parse;
+
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * 
+ * @author Jeremy Daggett
+ */
+@Test(groups = "unit", testName = "ParseMetadataItemTest")
+public class ParseMetadataItemTest extends BaseItemParserTest<Map<String, String>> {
+
+   @Override
+   public String resource() {
+      return "/metadata_item.json";
+   }
+
+   @Override
+   @SelectJson("metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Map<String, String> expected() {
+      ImmutableMap<String, String> metadata = ImmutableMap.of("Server Label", "Web Head 1");
+      return metadata;
+   }
+
+   protected Injector injector() {
+      return Guice.createInjector(new NovaParserModule(), new GsonModule());
+   }
+
+}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataListTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataListTest.java
new file mode 100644
index 0000000..db195fc
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataListTest.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.parse;
+
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * 
+ * @author Jeremy Daggett
+ */
+@Test(groups = "unit", testName = "ParseMetadataListTest")
+public class ParseMetadataListTest extends BaseItemParserTest<Map<String, String>> {
+
+   @Override
+   public String resource() {
+      return "/metadata_list.json";
+   }
+
+   @Override
+   @SelectJson("metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Map<String, String> expected() {
+	  ImmutableMap<String, String> metadata =
+         new ImmutableMap.Builder<String, String>()
+               .put("Server Label", "Web Head 1")
+               .put("Image Version", "2.1")
+               .build();
+	  
+      return metadata;
+   }
+
+   protected Injector injector() {
+      return Guice.createInjector(new NovaParserModule(), new GsonModule());
+   }
+
+}
diff --git a/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataUpdateTest.java b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataUpdateTest.java
new file mode 100644
index 0000000..dc08093
--- /dev/null
+++ b/apis/openstack-nova/src/test/java/org/jclouds/openstack/nova/v2_0/parse/ParseMetadataUpdateTest.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.nova.v2_0.parse;
+
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.json.BaseItemParserTest;
+import org.jclouds.json.config.GsonModule;
+import org.jclouds.openstack.nova.v2_0.config.NovaParserModule;
+import org.jclouds.rest.annotations.SelectJson;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ * 
+ * @author Jeremy Daggett
+ */
+@Test(groups = "unit", testName = "ParseMetadataUpdateTest")
+public class ParseMetadataUpdateTest extends BaseItemParserTest<Map<String, String>> {
+
+   @Override
+   public String resource() {
+      return "/metadata_updated.json";
+   }
+
+   @Override
+   @SelectJson("metadata")
+   @Consumes(MediaType.APPLICATION_JSON)
+   public Map<String, String> expected() {
+      ImmutableMap<String, String> metadata =
+         new ImmutableMap.Builder<String, String>()
+               .put("Server Label", "Web Head 2")
+               .put("Image Version", "2.1")
+               .put("Server Description", "Simple Server")
+               .build();
+  
+      return metadata;
+   }
+
+   protected Injector injector() {
+      return Guice.createInjector(new NovaParserModule(), new GsonModule());
+   }
+
+}
diff --git a/apis/openstack-nova/src/test/resources/metadata_item.json b/apis/openstack-nova/src/test/resources/metadata_item.json
new file mode 100644
index 0000000..f853109
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/metadata_item.json
@@ -0,0 +1,5 @@
+{ 
+    "metadata": {
+        "Server Label": "Web Head 1"
+    }
+}
\ No newline at end of file
diff --git a/apis/openstack-nova/src/test/resources/metadata_list.json b/apis/openstack-nova/src/test/resources/metadata_list.json
new file mode 100644
index 0000000..174d7d6
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/metadata_list.json
@@ -0,0 +1,6 @@
+{ 
+    "metadata": {
+        "Server Label": "Web Head 1",
+        "Image Version": "2.1"
+    }
+}
\ No newline at end of file
diff --git a/apis/openstack-nova/src/test/resources/metadata_updated.json b/apis/openstack-nova/src/test/resources/metadata_updated.json
new file mode 100644
index 0000000..82d9fd3
--- /dev/null
+++ b/apis/openstack-nova/src/test/resources/metadata_updated.json
@@ -0,0 +1,7 @@
+{ 
+    "metadata": {
+        "Server Label": "Web Head 2",
+        "Image Version": "2.1",
+        "Server Description": "Simple Server"
+    }
+}
\ No newline at end of file
diff --git a/apis/pom.xml b/apis/pom.xml
index bde1678..29c3c5a 100644
--- a/apis/pom.xml
+++ b/apis/pom.xml
@@ -54,5 +54,6 @@
        <module>cloudsigma</module>
        <module>cloudstack</module>
        <module>rackspace-cloudidentity</module>
+       <module>sqs</module>
     </modules>
 </project>
diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java
index 45aa6ba..71718ed 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java
@@ -70,11 +70,21 @@
    }
 
    @Override
+   public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signPutBlob(String container, Blob blob) {
       return cleanRequest(processor.createRequest(createMethod, container, blobToObject.apply(blob)));
    }
 
    @Override
+   public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signRemoveBlob(String container, String name) {
       return cleanRequest(processor.createRequest(deleteMethod, container, name));
    }
diff --git a/apis/sqs/pom.xml b/apis/sqs/pom.xml
new file mode 100644
index 0000000..83f4cbf
--- /dev/null
+++ b/apis/sqs/pom.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to jclouds, Inc. (jclouds) under one or more
+    contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  jclouds licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.jclouds</groupId>
+        <artifactId>jclouds-project</artifactId>
+        <version>1.5.0-SNAPSHOT</version>
+        <relativePath>../../project/pom.xml</relativePath>
+    </parent>
+    <groupId>org.jclouds.api</groupId>
+    <artifactId>sqs</artifactId>
+    <name>jcloud sqs api</name>
+    <description>jclouds components to access an implementation of Simple Queue Service</description>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <test.sqs.endpoint>https://sqs.us-east-1.amazonaws.com</test.sqs.endpoint>
+        <test.sqs.api-version>2011-10-01</test.sqs.api-version>
+        <test.sqs.build-version></test.sqs.build-version>
+        <test.sqs.identity>${test.aws.identity}</test.sqs.identity>
+        <test.sqs.credential>${test.aws.credential}</test.sqs.credential>
+
+        <jclouds.osgi.export>org.jclouds.sqs*;version="${project.version}"</jclouds.osgi.export>
+        <jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jclouds.common</groupId>
+            <artifactId>aws-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds.driver</groupId>
+            <artifactId>jclouds-log4j</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>live</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        <test.sqs.endpoint>${test.sqs.endpoint}</test.sqs.endpoint>
+                                        <test.sqs.api-version>${test.sqs.api-version}</test.sqs.api-version>
+                                        <test.sqs.build-version>${test.sqs.build-version}</test.sqs.build-version>
+                                        <test.sqs.identity>${test.sqs.identity}</test.sqs.identity>
+                                        <test.sqs.credential>${test.sqs.credential}</test.sqs.credential>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/SQSApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/SQSApi.java
new file mode 100644
index 0000000..8804e24
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/SQSApi.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs;
+
+import java.net.URI;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.Region;
+import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
+import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.EndpointParam;
+import org.jclouds.sqs.features.MessageApi;
+import org.jclouds.sqs.features.PermissionApi;
+import org.jclouds.sqs.features.QueueApi;
+
+import com.google.common.annotations.Beta;
+import com.google.inject.Provides;
+
+/**
+ * Provides access to SQS via their REST API.
+ * <p/>
+ * 
+ * @author Adrian Cole
+ * @see SQSAsyncApi
+ */
+@Beta
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface SQSApi {
+   
+   /**
+    * 
+    * @return the Region codes configured
+    */
+   @Provides
+   @Region
+   Set<String> getConfiguredRegions();
+
+   /**
+    * Provides synchronous access to Queue features.
+    */
+   @Delegate
+   QueueApi getQueueApi();
+
+   @Delegate
+   QueueApi getQueueApiForRegion(@EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+
+   /**
+    * Provides synchronous access to Message features.
+    */
+   @Delegate
+   MessageApi getMessageApiForQueue(@EndpointParam URI queue);
+
+   /**
+    * Provides synchronous access to Permission features.
+    */
+   @Delegate
+   PermissionApi getPermissionApiForQueue(@EndpointParam URI queue);
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/SQSApiMetadata.java b/apis/sqs/src/main/java/org/jclouds/sqs/SQSApiMetadata.java
new file mode 100644
index 0000000..04081df
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/SQSApiMetadata.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs;
+
+import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
+import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
+import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_MAX_RETRIES;
+import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_RETRY_INTERVAL;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.rest.RestContext;
+import org.jclouds.rest.internal.BaseRestApiMetadata;
+import org.jclouds.sqs.config.SQSRestClientModule;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for Amazon's Simple Queue Service api.
+ * 
+ * @author Adrian Cole
+ */
+public class SQSApiMetadata extends BaseRestApiMetadata {
+
+   /** The serialVersionUID */
+   private static final long serialVersionUID = -7077953935392202824L;
+   
+   public static final TypeToken<RestContext<SQSApi, SQSAsyncApi>> CONTEXT_TOKEN = new TypeToken<RestContext<SQSApi, SQSAsyncApi>>() {
+      private static final long serialVersionUID = -5070937833892503232L;
+   };
+
+   @Override
+   public Builder toBuilder() {
+      return new Builder(getApi(), getAsyncApi()).fromApiMetadata(this);
+   }
+
+   public SQSApiMetadata() {
+      this(new Builder(SQSApi.class, SQSAsyncApi.class));
+   }
+
+   protected SQSApiMetadata(Builder builder) {
+      super(builder);
+   }
+   
+   public static Properties defaultProperties() {
+      Properties properties = BaseRestApiMetadata.defaultProperties();
+      properties.setProperty(CREATE_QUEUE_MAX_RETRIES, "60");
+      properties.setProperty(CREATE_QUEUE_RETRY_INTERVAL, "1000");
+      properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
+      properties.setProperty(PROPERTY_HEADER_TAG, "amz");
+      return properties;
+   }
+   
+   public static class Builder extends BaseRestApiMetadata.Builder {
+
+      protected Builder(Class<?> api, Class<?> asyncApi) {
+         super(api, asyncApi);
+         id("sqs")
+         .name("Amazon Simple Queue Service API")
+         .identityName("Access Key ID")
+         .credentialName("Secret Access Key")
+         .version("2011-10-01")
+         .defaultProperties(SQSApiMetadata.defaultProperties())
+         .defaultEndpoint("https://sqs.us-east-1.amazonaws.com")
+         .documentation(URI.create("http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference"))
+         .defaultModules(ImmutableSet.<Class<? extends Module>>of(SQSRestClientModule.class));
+      }
+
+      @Override
+      public SQSApiMetadata build() {
+         return new SQSApiMetadata(this);
+      }
+      
+      @Override
+      public Builder fromApiMetadata(ApiMetadata in) {
+         super.fromApiMetadata(in);
+         return this;
+      }
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/SQSAsyncApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/SQSAsyncApi.java
new file mode 100644
index 0000000..c9a8f0e
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/SQSAsyncApi.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs;
+
+import java.net.URI;
+import java.util.Set;
+
+import org.jclouds.aws.filters.FormSigner;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.Region;
+import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
+import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.EndpointParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.VirtualHost;
+import org.jclouds.sqs.features.MessageAsyncApi;
+import org.jclouds.sqs.features.PermissionAsyncApi;
+import org.jclouds.sqs.features.QueueAsyncApi;
+
+import com.google.common.annotations.Beta;
+import com.google.inject.Provides;
+
+/**
+ * Provides access to SQS via REST API.
+ * <p/>
+ * 
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Welcome.html">SQS
+ *      documentation</a>
+ * @author Adrian Cole
+ */
+@Beta
+@RequestFilters(FormSigner.class)
+@VirtualHost
+public interface SQSAsyncApi {
+   /**
+    * 
+    * @return the Region codes configured
+    */
+   @Provides
+   @Region
+   Set<String> getConfiguredRegions();
+
+   /**
+    * Provides asynchronous access to Queue features.
+    */
+   @Delegate
+   QueueAsyncApi getQueueApi();
+
+   @Delegate
+   QueueAsyncApi getQueueApiForRegion(
+         @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region);
+
+   /**
+    * Provides asynchronous access to Message features.
+    */
+   @Delegate
+   MessageAsyncApi getMessageApiForQueue(@EndpointParam URI queue);
+
+   /**
+    * Provides asynchronous access to Permission features.
+    */
+   @Delegate
+   PermissionAsyncApi getPermissionApiForQueue(@EndpointParam URI queue);
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindAttributeNamesToIndexedFormParams.java b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindAttributeNamesToIndexedFormParams.java
new file mode 100644
index 0000000..13edefe
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindAttributeNamesToIndexedFormParams.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.binders;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableMultimap.Builder;
+
+/**
+ * Binds the Iterable<String> to form parameters named with AttributeName.index
+ * 
+ * @author Adrian Cole
+ */
+@Singleton
+public class BindAttributeNamesToIndexedFormParams implements Binder {
+
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      Iterable<?> values = Iterable.class.cast(checkNotNull(input, "attributeNames"));
+      Builder<String, String> builder = ImmutableMultimap.builder();
+      int i = 0;
+      for (Object o : values) {
+         builder.put("AttributeName." + (i++ + 1), o.toString());
+      }
+      ImmutableMultimap<String, String> forms = builder.build();
+      return (R) (forms.size() == 0 ? request : request.toBuilder().replaceFormParams(forms).build());
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams.java b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams.java
new file mode 100644
index 0000000..1a722aa
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.binders;
+
+import java.util.Map;
+
+import org.jclouds.aws.binders.BindTableToIndexedFormParams;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.MapBinder;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.ImmutableTable.Builder;
+import com.google.common.collect.Maps;
+
+/**
+ * @author Adrian Cole
+ */
+public class BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams extends BindTableToIndexedFormParams
+      implements MapBinder {
+
+   protected BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams() {
+      super("ChangeMessageVisibilityBatchRequestEntry.%d.Id",
+            "ChangeMessageVisibilityBatchRequestEntry.%d.ReceiptHandle",
+            "ChangeMessageVisibilityBatchRequestEntry.%d.VisibilityTimeout");
+   }
+
+   public Map<String, String> idReceiptHandle(Iterable<String> input) {
+      return Maps.uniqueIndex((Iterable<String>) input, new Function<String, String>() {
+         int index = 1;
+
+         @Override
+         public String apply(String input) {
+            return index++ + "";
+         }
+      });
+   }
+
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      Map<String, String> idReceiptHandle = (Map<String, String>) postParams.get("idReceiptHandle");
+      if (idReceiptHandle == null) {
+         idReceiptHandle = idReceiptHandle((Iterable<String>) postParams.get("receiptHandles"));
+      }
+      int visibilityTimeout = (Integer) postParams.get("visibilityTimeout");
+
+      Builder<Object, Object, Object> builder = ImmutableTable.builder();
+      for (Map.Entry<?, ?> entry : idReceiptHandle.entrySet())
+         builder.put(entry.getKey(), entry.getValue(), visibilityTimeout);
+      return bindToRequest(request, (Object) builder.build());
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindDeleteMessageBatchRequestEntryToIndexedFormParams.java b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindDeleteMessageBatchRequestEntryToIndexedFormParams.java
new file mode 100644
index 0000000..dd1ba5e
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindDeleteMessageBatchRequestEntryToIndexedFormParams.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.binders;
+
+import org.jclouds.aws.binders.BindMapToIndexedFormParams;
+
+/**
+ * @author Adrian Cole
+ */
+public class BindDeleteMessageBatchRequestEntryToIndexedFormParams extends BindMapToIndexedFormParams {
+
+   protected BindDeleteMessageBatchRequestEntryToIndexedFormParams() {
+      super("DeleteMessageBatchRequestEntry.%d.Id", "DeleteMessageBatchRequestEntry.%d.ReceiptHandle");
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindSendMessageBatchRequestEntryToIndexedFormParams.java b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindSendMessageBatchRequestEntryToIndexedFormParams.java
new file mode 100644
index 0000000..748c7d0
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindSendMessageBatchRequestEntryToIndexedFormParams.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.binders;
+
+import org.jclouds.aws.binders.BindMapToIndexedFormParams;
+
+/**
+ * @author Adrian Cole
+ */
+public class BindSendMessageBatchRequestEntryToIndexedFormParams extends BindMapToIndexedFormParams {
+
+   protected BindSendMessageBatchRequestEntryToIndexedFormParams() {
+      super("SendMessageBatchRequestEntry.%d.Id", "SendMessageBatchRequestEntry.%d.MessageBody");
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams.java b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams.java
new file mode 100644
index 0000000..0727a47
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/binders/BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.binders;
+
+import java.util.Map;
+
+import org.jclouds.aws.binders.BindTableToIndexedFormParams;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.MapBinder;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.ImmutableTable.Builder;
+import com.google.common.collect.Maps;
+
+/**
+ * @author Adrian Cole
+ */
+public class BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams extends BindTableToIndexedFormParams
+      implements MapBinder {
+
+   protected BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams() {
+      super("SendMessageBatchRequestEntry.%d.Id", "SendMessageBatchRequestEntry.%d.MessageBody",
+            "SendMessageBatchRequestEntry.%d.DelaySeconds");
+   }
+
+   public Map<String, String> idMessageBody(Iterable<String> input) {
+      return Maps.uniqueIndex((Iterable<String>) input, new Function<String, String>() {
+         int index = 1;
+
+         @Override
+         public String apply(String input) {
+            return index++ + "";
+         }
+      });
+   }
+
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      Map<String, String> idMessageBody = (Map<String, String>) postParams.get("idMessageBody");
+      if (idMessageBody == null) {
+         idMessageBody = idMessageBody((Iterable<String>) postParams.get("messageBodies"));
+      }
+      int delaySeconds = (Integer) postParams.get("delaySeconds");
+
+      Builder<Object, Object, Object> builder = ImmutableTable.builder();
+      for (Map.Entry<?, ?> entry : idMessageBody.entrySet())
+         builder.put(entry.getKey(), entry.getValue(), delaySeconds);
+      return bindToRequest(request, (Object) builder.build());
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/config/SQSProperties.java b/apis/sqs/src/main/java/org/jclouds/sqs/config/SQSProperties.java
new file mode 100644
index 0000000..5833672
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/config/SQSProperties.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.config;
+
+
+/**
+ * Configuration properties and constants used in SQS connections.
+ * 
+ * @author Adrian Cole
+ */
+public interface SQSProperties {
+
+   /**
+    * Integer property.
+    * <p/>
+    * When creating a queue, you can encounter
+    * {@code AWS.SimpleQueueService.QueueDeletedRecently}, which is typically a
+    * resolvable error. default tries are 60,
+    */
+   public static final String CREATE_QUEUE_MAX_RETRIES = "jclouds.sqs.create-queue.max-retries";
+
+   /**
+    * Long property.
+    * <p/>
+    * When creating a queue, you can encounter
+    * {@code AWS.SimpleQueueService.QueueDeletedRecently}, which is typically a
+    * resolvable error. default interval between tries is 1000 milliseconds (1
+    * second).
+    */
+   public static final String CREATE_QUEUE_RETRY_INTERVAL = "jclouds.sqs.create-queue.retry-interval";
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/config/SQSRestClientModule.java b/apis/sqs/src/main/java/org/jclouds/sqs/config/SQSRestClientModule.java
new file mode 100644
index 0000000..09b4882
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/config/SQSRestClientModule.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.config;
+
+import java.util.Map;
+
+import org.jclouds.aws.config.FormSigningRestClientModule;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.sqs.SQSApi;
+import org.jclouds.sqs.SQSAsyncApi;
+import org.jclouds.sqs.features.MessageApi;
+import org.jclouds.sqs.features.MessageAsyncApi;
+import org.jclouds.sqs.features.PermissionApi;
+import org.jclouds.sqs.features.PermissionAsyncApi;
+import org.jclouds.sqs.features.QueueApi;
+import org.jclouds.sqs.features.QueueAsyncApi;
+import org.jclouds.sqs.handlers.ParseSQSErrorFromXmlContent;
+import org.jclouds.sqs.handlers.SQSErrorRetryHandler;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Configures the SQS connection.
+ * 
+ * @author Adrian Cole
+ */
+@ConfiguresRestClient
+public class SQSRestClientModule extends FormSigningRestClientModule<SQSApi, SQSAsyncApi> {
+   public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
+         .put(QueueApi.class, QueueAsyncApi.class)
+         .put(MessageApi.class, MessageAsyncApi.class)
+         .put(PermissionApi.class, PermissionAsyncApi.class)
+         .build();
+
+   public SQSRestClientModule() {
+      super(TypeToken.of(SQSApi.class), TypeToken.of(SQSAsyncApi.class), DELEGATE_MAP);
+   }
+   
+   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseSQSErrorFromXmlContent.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseSQSErrorFromXmlContent.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseSQSErrorFromXmlContent.class);
+   }
+
+   @Override
+   protected void bindRetryHandlers() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(SQSErrorRetryHandler.class);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/domain/Action.java b/apis/sqs/src/main/java/org/jclouds/sqs/domain/Action.java
new file mode 100644
index 0000000..7a1f886
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/domain/Action.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.domain;
+
+import com.google.common.base.CaseFormat;
+
+/**
+ * 
+ * The action you want to allow for the specified principal.
+ * 
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/acp-overview.html#PermissionTypes"
+ *      />
+ * @author Adrian Cole
+ */
+public enum Action {
+   /**
+    * This permission type grants the following actions to a principal on a
+    * shared queue: receive messages, send messages, delete messages, change a
+    * message's visibility, get a queue's attributes.
+    */
+   ALL,
+   /**
+    * This grants permission to receive messages in the queue.
+    */
+   RECEIVE_MESSAGE,
+   /**
+    * This grants permission to send messages to the queue. SendMessageBatch
+    * inherits permissions associated with SendMessage.
+    */
+   SEND_MESSAGE,
+   /**
+    * This grants permission to delete messages from the queue.
+    * DeleteMessageBatch inherits permissions associated with DeleteMessage.
+    */
+   DELETE_MESSAGE,
+   /**
+    * This grants permission to extend or terminate the read lock timeout of a
+    * specified message. ChangeMessageVisibilityBatch inherits permissions
+    * associated with ChangeMessageVisibility. For more information about
+    * visibility timeout, see Visibility Timeout. For more information about
+    * this permission type, see the ChangeMessageVisibility operation.
+    */
+   CHANGE_MESSAGE_VISIBILITY,
+   /**
+    * This grants permission to receive all of the queue attributes except the
+    * policy, which can only be accessed by the queue's owner. For more
+    * information, see the GetQueueAttributes operation.
+    */
+   GET_QUEUE_ATTRIBUTES,
+   /**
+    * This grants permission to get the url of a queue by name.
+    */
+   GET_QUEUE_URL;
+
+   public String value() {
+      return this == ALL ? "*" : CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
+   }
+
+   @Override
+   public String toString() {
+      return value();
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/domain/Attribute.java b/apis/sqs/src/main/java/org/jclouds/sqs/domain/Attribute.java
new file mode 100644
index 0000000..048c692
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/domain/Attribute.java
@@ -0,0 +1,88 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy 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.sqs.domain;
+
+/**
+ * 
+ * The action you want to allow for the specified principal.
+ * 
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/acp-overview.html#PermissionTypes"
+ *      />
+ * @author Adrian Cole
+ */
+public interface Attribute {
+
+   /**
+    * approximate number of visible messages in a queue.
+    */
+   public static final String APPROXIMATE_NUMBER_OF_MESSAGES = "ApproximateNumberOfMessages";
+   /**
+    * approximate number of messages that are not timed-out and not deleted.
+    */
+   public static final String APPROXIMATE_NUMBER_OF_MESSAGES_NOT_VISIBLE = "ApproximateNumberOfMessagesNotVisible";
+
+   /**
+    * approximate number of messages that are not visible because you have set a
+    * positive delay value on the queue
+    */
+   public static final String APPROXIMATE_NUMBER_OF_MESSAGES_DELAYED = "ApproximateNumberOfMessagesDelayed";
+
+   /**
+    * visibility timeout for the queue.
+    */
+   public static final String VISIBILITY_TIMEOUT = "VisibilityTimeout";
+
+   /**
+    * time when the queue was created (epoch time in seconds).
+    */
+   public static final String CREATED_TIMESTAMP = "CreatedTimestamp";
+
+   /**
+    * time when the queue was last changed (epoch time in seconds).
+    */
+   public static final String LAST_MODIFIED_TIMESTAMP = "LastModifiedTimestamp";
+
+   /**
+    * queue's policy.
+    */
+   public static final String POLICY = "Policy";
+
+   /**
+    * limit of how many bytes a message can contain before Amazon SQS rejects
+    * it.
+    */
+   public static final String MAXIMUM_MESSAGE_SIZE = "MaximumMessageSize";
+
+   /**
+    * number of seconds Amazon SQS retains a message.
+    */
+   public static final String MESSAGE_RETENTION_PERIOD = "MessageRetentionPeriod";
+
+   /**
+    * queue's Amazon resource name (ARN).
+    */
+   public static final String QUEUE_ARN = "QueueArn";
+
+   /**
+    * The time in seconds that the delivery of all messages in the queue will be
+    * delayed.
+    */
+   public static final String DELAY_SECONDS = "DelaySeconds";
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/domain/BatchError.java b/apis/sqs/src/main/java/org/jclouds/sqs/domain/BatchError.java
new file mode 100644
index 0000000..45696f4
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/domain/BatchError.java
@@ -0,0 +1,155 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+
+/**
+ * 
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryDeleteMessageBatch.html"
+ *      >doc</a>
+ * 
+ * @author Adrian Cole
+ */
+public class BatchError {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromErrorEntry(this);
+   }
+
+   public static class Builder {
+
+      private String id;
+      private boolean senderFault;
+      private String code;
+      private String message;
+
+      /**
+       * @see BatchError#getId()
+       */
+      public Builder id(String id) {
+         this.id = id;
+         return this;
+      }
+
+      /**
+       * @see BatchError#isSenderFault()
+       */
+      public Builder senderFault(boolean senderFault) {
+         this.senderFault = senderFault;
+         return this;
+      }
+
+      /**
+       * @see BatchError#getCode()
+       */
+      public Builder code(String code) {
+         this.code = code;
+         return this;
+      }
+
+      /**
+       * @see BatchError#getMessage()
+       */
+      public Builder message(String message) {
+         this.message = message;
+         return this;
+      }
+
+      public BatchError build() {
+         return new BatchError(id, senderFault, code, message);
+      }
+
+      public Builder fromErrorEntry(BatchError in) {
+         return id(in.getId()).senderFault(in.isSenderFault()).code(in.getCode()).message(in.getMessage());
+      }
+   }
+
+   private final String id;
+   private final boolean senderFault;
+   private final String code;
+   private final String message;
+
+   private BatchError(String id, boolean senderFault, String code, String message) {
+      this.id = checkNotNull(id, "id");
+      this.senderFault = checkNotNull(senderFault, "senderFault of %s", id);
+      this.code = checkNotNull(code, "code of %s", id);
+      this.message = checkNotNull(message, "message of %s", id);
+   }
+
+   /**
+    * The Id name that you assigned to the message.
+    */
+   public String getId() {
+      return id;
+   }
+
+   /**
+    * 
+    */
+   public boolean isSenderFault() {
+      return senderFault;
+   }
+
+   /**
+    * A short string description of the error.
+    */
+   public String getCode() {
+      return code;
+   }
+
+   /**
+    * A description of the error.
+    */
+   public String getMessage() {
+      return message;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      BatchError that = BatchError.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id).add("senderFault", senderFault)
+            .add("message", message).add("code", code).toString();
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/domain/BatchResult.java b/apis/sqs/src/main/java/org/jclouds/sqs/domain/BatchResult.java
new file mode 100644
index 0000000..cbb2d4b
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/domain/BatchResult.java
@@ -0,0 +1,146 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.ForwardingMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+
+/**
+ * 
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/MessageLifecycle.html"
+ *      >doc</a>
+ * 
+ * @author Adrian Cole
+ */
+public class BatchResult<V> extends ForwardingMap<String, V> {
+
+   public static <V> Builder<V> builder() {
+      return new Builder<V>();
+   }
+
+   public Builder<V> toBuilder() {
+      return BatchResult.<V> builder().fromBatchResult(this);
+   }
+
+   public static class Builder<V> {
+
+      private ImmutableMap.Builder<String, V> results = ImmutableMap.<String, V> builder();
+      private ImmutableSet.Builder<BatchError> errors = ImmutableSet.<BatchError> builder();
+
+      /**
+       * @see BatchResult#getErrors()
+       */
+      public Builder<V> addError(BatchError error) {
+         this.errors.add(checkNotNull(error, "error"));
+         return this;
+      }
+
+      /**
+       * @see BatchResult#getErrors()
+       */
+      public Builder<V> errors(Iterable<BatchError> errors) {
+         this.errors = ImmutableSet.<BatchError> builder().addAll(checkNotNull(errors, "errors"));
+         return this;
+      }
+
+      /**
+       * @see BatchResult#get
+       */
+      public Builder<V> putAll(Map<String, V> results) {
+         this.results.putAll(checkNotNull(results, "results"));
+         return this;
+      }
+
+      /**
+       * @see BatchResult#get
+       */
+      public Builder<V> put(String name, V value) {
+         this.results.put(checkNotNull(name, "name"), checkNotNull(value, "value"));
+         return this;
+      }
+
+      public BatchResult<V> build() {
+         return new BatchResult<V>(results.build(), errors.build());
+      }
+
+      public Builder<V> fromBatchResult(BatchResult<V> in) {
+         return putAll(in).errors(in.getErrors().values());
+      }
+   }
+
+   private final Map<String, V> results;
+   private final Map<String, BatchError> errors;
+
+   private BatchResult(Map<String, V> results, Iterable<BatchError> errors) {
+      this.results = ImmutableMap.copyOf(checkNotNull(results, "results"));
+      this.errors = Maps.uniqueIndex(checkNotNull(errors, "errors"), new Function<BatchError, String>() {
+         @Override
+         public String apply(BatchError in) {
+            return in.getId();
+         }
+
+      });
+   }
+
+   @Override
+   protected Map<String, V> delegate() {
+      return results;
+   }
+
+   /**
+    * Errors indexed by requestor supplied id
+    */
+   public Map<String, BatchError> getErrors() {
+      return errors;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(results, errors);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      @SuppressWarnings("unchecked")
+      BatchResult<V> that = BatchResult.class.cast(obj);
+      return Objects.equal(this.results, that.results) && Objects.equal(this.errors, that.errors);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("results", results).add("errors", errors).toString();
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/domain/Message.java b/apis/sqs/src/main/java/org/jclouds/sqs/domain/Message.java
new file mode 100644
index 0000000..37d0c91
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/domain/Message.java
@@ -0,0 +1,186 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.hash.HashCode;
+
+/**
+ * 
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/MessageLifecycle.html"
+ *      >doc</a>
+ * 
+ * @author Adrian Cole
+ */
+public class Message {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromMessage(this);
+   }
+
+   public static class Builder {
+
+      private String id;
+      private String body;
+      private String receiptHandle;
+      private HashCode md5;
+      private ImmutableMap.Builder<String, String> attributes = ImmutableMap.<String, String> builder();
+
+      /**
+       * @see Message#getId()
+       */
+      public Builder id(String id) {
+         this.id = id;
+         return this;
+      }
+
+      /**
+       * @see Message#getBody()
+       */
+      public Builder body(String body) {
+         this.body = body;
+         return this;
+      }
+
+      /**
+       * @see Message#getReceiptHandle()
+       */
+      public Builder receiptHandle(String receiptHandle) {
+         this.receiptHandle = receiptHandle;
+         return this;
+      }
+
+      /**
+       * @see Message#getMD5()
+       */
+      public Builder md5(HashCode md5) {
+         this.md5 = md5;
+         return this;
+      }
+
+      /**
+       * @see Message#getAttributes()
+       */
+      public Builder attributes(Map<String, String> attributes) {
+         this.attributes.putAll(checkNotNull(attributes, "attributes"));
+         return this;
+      }
+
+      /**
+       * @see Message#getAttributes()
+       */
+      public Builder addAttribute(String name, String value) {
+         this.attributes.put(checkNotNull(name, "name"), checkNotNull(value, "value"));
+         return this;
+      }
+
+      public Message build() {
+         return new Message(id, body, receiptHandle, md5, attributes.build());
+      }
+
+      public Builder fromMessage(Message in) {
+         return id(in.getId()).body(in.getBody()).receiptHandle(in.getReceiptHandle()).md5(in.getMD5())
+               .attributes(in.getAttributes());
+      }
+   }
+
+   private final String id;
+   private final String body;
+   private final String receiptHandle;
+   private final HashCode md5;
+   private final Map<String, String> attributes;
+
+   private Message(String id, String body, String receiptHandle, HashCode md5, Map<String, String> attributes) {
+      this.id = checkNotNull(id, "id");
+      this.body = checkNotNull(body, "body of %s", id);
+      this.receiptHandle = checkNotNull(receiptHandle, "receiptHandle of %s", id);
+      this.md5 = checkNotNull(md5, "md5 of %s", id);
+      this.attributes = ImmutableMap.copyOf(checkNotNull(attributes, "attributes of %s", id));
+   }
+
+   /**
+    * The message's SQS-assigned ID.
+    */
+   public String getId() {
+      return id;
+   }
+
+   /**
+    * The message's contents (not URL encoded)
+    */
+   public String getBody() {
+      return body;
+   }
+
+   /**
+    * A string associated with a specific instance of receiving the message.
+    */
+   public String getReceiptHandle() {
+      return receiptHandle;
+   }
+
+   /**
+    * An MD5 digest of the non-URL-encoded message body string
+    */
+   public HashCode getMD5() {
+      return md5;
+   }
+
+   /**
+    * Attributes of the queue
+    */
+   public Map<String, String> getAttributes() {
+      return attributes;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      Message that = Message.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id).add("body", body).add("md5", md5)
+            .add("receiptHandle", receiptHandle).add("attributes", attributes).toString();
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/domain/MessageIdAndMD5.java b/apis/sqs/src/main/java/org/jclouds/sqs/domain/MessageIdAndMD5.java
new file mode 100644
index 0000000..897f69d
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/domain/MessageIdAndMD5.java
@@ -0,0 +1,119 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Objects;
+import com.google.common.hash.HashCode;
+
+/**
+ * 
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/MessageLifecycle.html"
+ *      >doc</a>
+ * 
+ * @author Adrian Cole
+ */
+public class MessageIdAndMD5 {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromMessage(this);
+   }
+
+   public static class Builder {
+
+      private String id;
+      private HashCode md5;
+
+      /**
+       * @see MessageIdAndMD5#getId()
+       */
+      public Builder id(String id) {
+         this.id = id;
+         return this;
+      }
+
+      /**
+       * @see MessageIdAndMD5#getMD5()
+       */
+      public Builder md5(HashCode md5) {
+         this.md5 = md5;
+         return this;
+      }
+
+      public MessageIdAndMD5 build() {
+         return new MessageIdAndMD5(id, md5);
+      }
+
+      public Builder fromMessage(MessageIdAndMD5 in) {
+         return id(in.getId()).md5(in.getMD5());
+      }
+   }
+
+   private final String id;
+   private final HashCode md5;
+
+   private MessageIdAndMD5(String id, HashCode md5) {
+      this.id = checkNotNull(id, "id");
+      this.md5 = checkNotNull(md5, "md5 of %s", id);
+   }
+
+   /**
+    * The message's SQS-assigned ID.
+    */
+   public String getId() {
+      return id;
+   }
+
+   /**
+    * An MD5 digest of the non-URL-encoded message body string
+    */
+   public HashCode getMD5() {
+      return md5;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      MessageIdAndMD5 that = MessageIdAndMD5.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id).add("md5", md5).toString();
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/domain/QueueAttributes.java b/apis/sqs/src/main/java/org/jclouds/sqs/domain/QueueAttributes.java
new file mode 100644
index 0000000..d2e1e2c
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/domain/QueueAttributes.java
@@ -0,0 +1,314 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Date;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+
+/**
+ * 
+ * @author Adrian Cole
+ * 
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryGetQueueAttributes.html"
+ *      />
+ */
+public class QueueAttributes {
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromQueueAttributes(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected String queueArn;
+      protected long approximateNumberOfMessages;
+      protected long approximateNumberOfMessagesNotVisible;
+      protected long approximateNumberOfMessagesDelayed;
+      protected int visibilityTimeout;
+      protected Date createdTimestamp;
+      protected Date lastModifiedTimestamp;
+      protected Optional<String> rawPolicy = Optional.absent();
+      protected int maximumMessageSize;
+      protected int messageRetentionPeriod;
+      protected int delaySeconds;
+
+      /**
+       * @see QueueAttributes#getQueueArn()
+       */
+      public T queueArn(String queueArn) {
+         this.queueArn = queueArn;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getApproximateNumberOfMessages()
+       */
+      public T approximateNumberOfMessages(long approximateNumberOfMessages) {
+         this.approximateNumberOfMessages = approximateNumberOfMessages;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getApproximateNumberOfMessagesNotVisible()
+       */
+      public T approximateNumberOfMessagesNotVisible(long approximateNumberOfMessagesNotVisible) {
+         this.approximateNumberOfMessagesNotVisible = approximateNumberOfMessagesNotVisible;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getApproximateNumberOfMessagesDelayed()
+       */
+      public T approximateNumberOfMessagesDelayed(long approximateNumberOfMessagesDelayed) {
+         this.approximateNumberOfMessagesDelayed = approximateNumberOfMessagesDelayed;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getVisibilityTimeout()
+       */
+      public T visibilityTimeout(int visibilityTimeout) {
+         this.visibilityTimeout = visibilityTimeout;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getCreatedTimestamp()
+       */
+      public T createdTimestamp(Date createdTimestamp) {
+         this.createdTimestamp = createdTimestamp;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getLastModifiedTimestamp()
+       */
+      public T lastModifiedTimestamp(Date lastModifiedTimestamp) {
+         this.lastModifiedTimestamp = lastModifiedTimestamp;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getRawPolicy()
+       */
+      public T rawPolicy(String rawPolicy) {
+         this.rawPolicy = Optional.fromNullable(rawPolicy);
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getMaximumMessageSize()
+       */
+      public T maximumMessageSize(int maximumMessageSize) {
+         this.maximumMessageSize = maximumMessageSize;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getMessageRetentionPeriod()
+       */
+      public T messageRetentionPeriod(int messageRetentionPeriod) {
+         this.messageRetentionPeriod = messageRetentionPeriod;
+         return self();
+      }
+
+      /**
+       * @see QueueAttributes#getDelaySeconds()
+       */
+      public T delaySeconds(int delaySeconds) {
+         this.delaySeconds = delaySeconds;
+         return self();
+      }
+
+      public QueueAttributes build() {
+         return new QueueAttributes(queueArn, approximateNumberOfMessages, approximateNumberOfMessagesNotVisible,
+               approximateNumberOfMessagesDelayed, visibilityTimeout, createdTimestamp, lastModifiedTimestamp,
+               rawPolicy, maximumMessageSize, messageRetentionPeriod, delaySeconds);
+      }
+
+      public T fromQueueAttributes(QueueAttributes in) {
+         return queueArn(in.queueArn).approximateNumberOfMessages(in.approximateNumberOfMessages)
+               .approximateNumberOfMessagesNotVisible(in.approximateNumberOfMessagesNotVisible)
+               .approximateNumberOfMessagesDelayed(in.approximateNumberOfMessagesDelayed)
+               .visibilityTimeout(in.visibilityTimeout).createdTimestamp(in.createdTimestamp)
+               .lastModifiedTimestamp(in.lastModifiedTimestamp).rawPolicy(in.rawPolicy.orNull())
+               .maximumMessageSize(in.maximumMessageSize).messageRetentionPeriod(in.messageRetentionPeriod)
+               .delaySeconds(in.delaySeconds);
+
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   protected final long approximateNumberOfMessages;
+   protected final long approximateNumberOfMessagesNotVisible;
+   protected final int visibilityTimeout;
+   protected final Date createdTimestamp;
+   protected final Date lastModifiedTimestamp;
+   protected final long approximateNumberOfMessagesDelayed;
+   protected final Optional<String> rawPolicy;
+   protected final int maximumMessageSize;
+   protected final int messageRetentionPeriod;
+   protected final String queueArn;
+   protected int delaySeconds;
+
+   protected QueueAttributes(String queueArn, long approximateNumberOfMessages,
+         long approximateNumberOfMessagesNotVisible, long approximateNumberOfMessagesDelayed, int visibilityTimeout,
+         Date createdTimestamp, Date lastModifiedTimestamp, Optional<String> rawPolicy, int maximumMessageSize,
+         int messageRetentionPeriod, int delaySeconds) {
+      this.queueArn = checkNotNull(queueArn, "queueArn");
+      this.approximateNumberOfMessages = approximateNumberOfMessages;
+      this.approximateNumberOfMessagesNotVisible = approximateNumberOfMessagesNotVisible;
+      this.approximateNumberOfMessagesDelayed = approximateNumberOfMessagesDelayed;
+      this.visibilityTimeout = visibilityTimeout;
+      this.createdTimestamp = checkNotNull(createdTimestamp, "createdTimestamp of %s", queueArn);
+      this.lastModifiedTimestamp = checkNotNull(lastModifiedTimestamp, "lastModifiedTimestamp of %s", queueArn);
+      this.rawPolicy = checkNotNull(rawPolicy, "rawPolicy of %s", queueArn);
+      this.maximumMessageSize = maximumMessageSize;
+      this.messageRetentionPeriod = messageRetentionPeriod;
+      this.delaySeconds = delaySeconds;
+   }
+
+   /**
+    * @see Attribute#QUEUE_ARN
+    */
+   public String getQueueArn() {
+      return queueArn;
+   }
+
+   /**
+    * @see Attribute#APPROXIMATE_NUMBER_OF_MESSAGES
+    */
+   public long getApproximateNumberOfMessages() {
+      return approximateNumberOfMessages;
+   }
+
+   /**
+    * @see Attribute#APPROXIMATE_NUMBER_OF_MESSAGES_NOT_VISIBLE
+    */
+   public long getApproximateNumberOfMessagesNotVisible() {
+      return approximateNumberOfMessagesNotVisible;
+   }
+
+   /**
+    * @see Attribute#APPROXIMATE_NUMBER_OF_MESSAGES_DELAYED
+    */
+   public long getApproximateNumberOfMessagesDelayed() {
+      return approximateNumberOfMessagesDelayed;
+   }
+
+   /**
+    * @see Attribute#VISIBILITY_TIMEOUT
+    */
+   public int getVisibilityTimeout() {
+      return visibilityTimeout;
+   }
+
+   /**
+    * @see Attribute#CREATED_TIMESTAMP
+    */
+   public Date getCreatedTimestamp() {
+      return createdTimestamp;
+   }
+
+   /**
+    * @see Attribute#LAST_MODIFIED_TIMESTAMP
+    */
+   public Date getLastModifiedTimestamp() {
+      return lastModifiedTimestamp;
+   }
+
+   /**
+    * Note this is in raw Json
+    * 
+    * @see Attribute#POLICY
+    */
+   public Optional<String> getRawPolicy() {
+      return rawPolicy;
+   }
+
+   /**
+    * @see Attribute#MAXIMUM_MESSAGE_SIZE
+    */
+   public int getMaximumMessageSize() {
+      return maximumMessageSize;
+   }
+
+   /**
+    * @see Attribute#MESSAGE_RETENTION_PERIOD
+    */
+   public int getMessageRetentionPeriod() {
+      return messageRetentionPeriod;
+   }
+
+   /**
+    * @see Attribute#DELAY_SECONDS
+    */
+   public int getDelaySeconds() {
+      return delaySeconds;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(queueArn);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      QueueAttributes other = (QueueAttributes) obj;
+      return Objects.equal(this.queueArn, other.queueArn);
+
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("queueArn", queueArn)
+            .add("approximateNumberOfMessages", approximateNumberOfMessages)
+            .add("approximateNumberOfMessagesNotVisible", approximateNumberOfMessagesNotVisible)
+            .add("approximateNumberOfMessagesDelayed", approximateNumberOfMessagesDelayed)
+            .add("visibilityTimeout", visibilityTimeout).add("createdTimestamp", createdTimestamp)
+            .add("lastModifiedTimestamp", lastModifiedTimestamp).add("rawPolicy", rawPolicy.orNull())
+            .add("maximumMessageSize", maximumMessageSize).add("messageRetentionPeriod", messageRetentionPeriod)
+            .add("delaySeconds", delaySeconds).toString();
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/features/MessageApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/features/MessageApi.java
new file mode 100644
index 0000000..1ff505b
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/features/MessageApi.java
@@ -0,0 +1,419 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.sqs.domain.BatchResult;
+import org.jclouds.sqs.domain.Message;
+import org.jclouds.sqs.domain.MessageIdAndMD5;
+import org.jclouds.sqs.options.ReceiveMessageOptions;
+import org.jclouds.sqs.options.SendMessageOptions;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Table;
+
+/**
+ * Provides access to SQS via their REST API.
+ * <p/>
+ * 
+ * @see MessageAsyncApi
+ * @author Adrian Cole
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface MessageApi {
+
+   /**
+    * The DeleteMessage action deletes the specified message from the specified
+    * queue. You specify the message by using the message's receipt handle and
+    * not the message ID you received when you sent the message. Even if the
+    * message is locked by another reader due to the visibility timeout setting,
+    * it is still deleted from the queue. If you leave a message in the queue
+    * for more than 4 days, SQS automatically deletes it.
+    * 
+    * <h4>Note</h4>
+    * 
+    * The receipt handle is associated with a specific instance of receiving the
+    * message. If you receive a message more than once, the receipt handle you
+    * get each time you receive the message is different. When you request
+    * DeleteMessage, if you don't provide the most recently received receipt
+    * handle for the message, the request will still succeed, but the message
+    * might not be deleted.
+    * 
+    * <h4>Important</h4>
+    * 
+    * It is possible you will receive a message even after you have deleted it.
+    * This might happen on rare occasions if one of the servers storing a copy
+    * of the message is unavailable when you request to delete the message. The
+    * copy remains on the server and might be returned to you again on a
+    * subsequent receive request. You should create your system to be idempotent
+    * so that receiving a particular message more than once is not a problem.
+    * 
+    * @param queue
+    *           the queue the message is in
+    * @param receiptHandle
+    *           The receipt handle associated with the message you want to
+    *           delete.
+    */
+   void delete(String receiptHandle);
+
+   /**
+    * Currently, you can send up to 10 {@link #delete} requests.
+    * 
+    * <h4>Example usage</h4>
+    * 
+    * <pre>
+    * BatchResult<String> results = api.delete(ImmutableMap.<String, String>builder()
+    *                                  .put("id1", "handle1")
+    *                                  .put("id2", "handle2")
+    *                                  .build());
+    * 
+    * if (results.keySet().equals(ImmutableSet.of("id", "id2"))
+    *    // all ok
+    * else
+    *   results.getErrors();
+    * </pre>
+    * 
+    * @param idReceiptHandle
+    *           id for correlating the result to receipt handle
+    * @return result that contains success or errors of the operation
+    * @see #delete(String)
+    */
+   BatchResult<String> delete(Map<String, String> idReceiptHandle);
+
+   /**
+    * Same as {@link #delete(Map)}, except that we generate numeric ids starting
+    * with {@code 1}
+    * 
+    * @param receiptHandles
+    *           receipt handles to delete
+    * @see #delete(Map)
+    */
+   BatchResult<String> delete(Iterable<String> receiptHandles);
+
+   /**
+    * The ChangeMessageVisibility action changes the visibility timeout of a
+    * specified message in a queue to a new value. The maximum allowed timeout
+    * value you can set the value to is 12 hours. This means you can't extend
+    * the timeout of a message in an existing queue to more than a total
+    * visibility timeout of 12 hours. (For more information visibility timeout,
+    * see Visibility Timeout in the Amazon SQS Developer Guide.)
+    * 
+    * For example, let's say the timeout for the queue is 30 seconds, and you
+    * receive a message. Once you're 20 seconds into the timeout for that
+    * message (i.e., you have 10 seconds left), you extend it by 60 seconds by
+    * calling ChangeMessageVisibility with VisibilityTimeoutset to 60 seconds.
+    * You have then changed the remaining visibility timeout from 10 seconds to
+    * 60 seconds.
+    * 
+    * <h4>Important</h4>
+    * 
+    * If you attempt to set the VisibilityTimeout to an amount more than the
+    * maximum time left, Amazon SQS returns an error. It will not automatically
+    * recalculate and increase the timeout to the maximum time remaining.
+    * 
+    * <h4>Important</h4>
+    * 
+    * Unlike with a queue, when you change the visibility timeout for a specific
+    * message, that timeout value is applied immediately but is not saved in
+    * memory for that message. If you don't delete a message after it is
+    * received, the visibility timeout for the message the next time it is
+    * received reverts to the original timeout value, not the value you set with
+    * the ChangeMessageVisibility action.
+    * 
+    * @param queue
+    *           the queue the message is in
+    * @param receiptHandle
+    *           The receipt handle associated with the message whose visibility
+    *           timeout you want to change. This parameter is returned by the
+    *           ReceiveMessage action.
+    * @param visibilityTimeout
+    *           The new value for the message's visibility timeout (in seconds)
+    *           from 0 to 43200 (maximum 12 hours)
+    */
+   void changeVisibility(String receiptHandle, int visibilityTimeout);
+
+   /**
+    * Currently, you can send up to 10 {@link #changeVisibility} requests.
+    * 
+    * action. <h4>Example usage</h4>
+    * 
+    * <pre>
+    * BatchResult<String> results = api.changeVisibility(ImmutableTable.<String, String, Integer>builder()
+    *                                  .put("id1", "handle1", 45)
+    *                                  .put("id2", "handle2", 10)
+    *                                  .build());
+    * 
+    * if (results.keySet().equals(ImmutableSet.of("id", "id2"))
+    *    // all ok
+    * else
+    *   results.getErrors();
+    * </pre>
+    * 
+    * @param idReceiptHandleVisibilityTimeout
+    *           id for correlating the result, receipt handle, and visibility
+    *           timeout
+    * @return result that contains success or errors of the operation
+    * @see #changeVisibility(String, int)
+    */
+   BatchResult<String> changeVisibility(Table<String, String, Integer> idReceiptHandleVisibilityTimeout);
+
+   /**
+    * Same as {@link #changeVisibility(Table)}, except that we generate numeric
+    * ids starting with {@code 1}
+    * 
+    * @param receiptHandleVisibilityTimeout
+    *           receipt handle to visibility timeout
+    * @see #changeVisibility(Table)
+    */
+   BatchResult<? extends MessageIdAndMD5> changeVisibility(Map<String, Integer> receiptHandleVisibilityTimeout);
+
+   /**
+    * Currently, you can send up to 10 {@link #changeVisibility} requests.
+    * 
+    * action. <h4>Example usage</h4>
+    * 
+    * <pre>
+    * BatchResult<String> results = api.changeVisibility(ImmutableMap.<String, String>builder()
+    *                                  .put("id1", "handle1")
+    *                                  .put("id2", "handle2")
+    *                                  .build(), 45);
+    * 
+    * if (results.keySet().equals(ImmutableSet.of("id", "id2"))
+    *    // all ok
+    * else
+    *   results.getErrors();
+    * </pre>
+    * 
+    * @param idReceiptHandle
+    *           id for correlating the result to receipt handle
+    * @param visibilityTimeout
+    *           The new value for the message's visibility timeout (in seconds).
+    * @return result that contains success or errors of the operation
+    * @see #changeVisibility(String, int)
+    */
+   BatchResult<String> changeVisibility(Map<String, String> idReceiptHandle, int visibilityTimeout);
+
+   /**
+    * Same as {@link #changeVisibility(Map, int)}, except that we generate
+    * numeric ids starting with {@code 1}
+    * 
+    * @param receiptHandles
+    *           receipt handles to change visibility
+    * @see #changeVisibility(Map, int)
+    */
+   BatchResult<String> changeVisibility(Iterable<String> receiptHandles, int visibilityTimeout);
+
+   /**
+    * The SendMessage action delivers a message to the specified queue. The
+    * maximum allowed message size is 64 KB.
+    * 
+    * <h4>Important</h4>
+    * 
+    * The following list shows the characters (in Unicode) allowed in your
+    * message, according to the W3C XML specification (for more information, go
+    * to http://www.w3.org/TR/REC-xml/#charsets). If you send any characters not
+    * included in the list, your request will be rejected.
+    * 
+    * 
+    * {@code #x9 | #xA | #xD | [#x20 to #xD7FF] | [#xE000 to #xFFFD] | [#x10000 to #x10FFFF]}
+    * 
+    * @param queue
+    *           queue you want to send to
+    * 
+    * @param message
+    *           Type: String maximum 64 KB in size. For a list of allowed
+    *           characters, see the preceding important note.
+    * @return id of the message and md5 of the content sent
+    */
+   MessageIdAndMD5 send(String message);
+
+   /**
+    * Same as {@link #send(Map)} except you can set a delay for each message in
+    * the request.
+    * 
+    * <h4>Example usage</h4>
+    * 
+    * <pre>
+    * BatchResult<? extends MessageIdAndMD5> results = api.sendWithDelays(ImmutableTable.<String, String, Integer>builder()
+    *                                  .put("id1", "test message one", 1)
+    *                                  .put("id2", "test message two", 10)
+    *                                  .build());
+    * 
+    * if (results.keySet().equals(ImmutableSet.of("id", "id2"))
+    *    // all ok
+    * else
+    *   results.getErrors();
+    * </pre>
+    * 
+    * @param idMessageBodyDelaySeconds
+    *           id for correlating the result, message body, and delay seconds
+    * 
+    * @return result that contains success or errors of the operation
+    * @see #send(String, SendMessageOptions)
+    */
+   BatchResult<? extends MessageIdAndMD5> sendWithDelays(Table<String, String, Integer> idMessageBodyDelaySeconds);
+
+   /**
+    * Same as {@link #sendWithDelays(Table)}, except that we generate numeric
+    * ids starting with {@code 1}
+    * 
+    * @param messageBodyDelaySeconds
+    *           message body to the delay desired
+    * @see #sendWithDelays(Table)
+    */
+   BatchResult<? extends MessageIdAndMD5> sendWithDelays(Map<String, Integer> messageBodyDelaySeconds);
+
+   /**
+    * Same as {@link #send(Map)} except you set a delay for all messages in the
+    * request
+    * 
+    * @param delaySeconds
+    *           The number of seconds to delay a specific message. Messages with
+    *           a positive DelaySeconds value become available for processing
+    *           after the delay time is finished.
+    * 
+    * @see #send(String, SendMessageOptions)
+    */
+   BatchResult<? extends MessageIdAndMD5> sendWithDelay(Map<String, String> idMessageBody, int delaySeconds);
+
+   /**
+    * Same as {@link #sendWithDelay(Map, int)}, except that we generate numeric
+    * ids starting with {@code 1}
+    * 
+    * @param messageBodies
+    *           message bodies to send
+    * @see #sendWithDelay(Map, int)
+    */
+   BatchResult<? extends MessageIdAndMD5> sendWithDelay(Iterable<String> messageBodies, int delaySeconds);
+
+   /**
+    * The SendMessageBatch action delivers up to ten messages to the specified
+    * queue. The maximum allowed individual message size is 64 KiB (65,536
+    * bytes).
+    * 
+    * The maximum total payload size (i.e., the sum of all a batch's individual
+    * message lengths) is also 64 KiB (65,536 bytes).
+    * 
+    * Currently, you can send up to 10 {@link #send} requests.
+    * 
+    * action. <h4>Example usage</h4>
+    * 
+    * <pre>
+    * BatchResult<? extends MessageIdAndMD5> results = api.send(ImmutableMap.<String, String>builder()
+    *                                  .put("id1", "test message one")
+    *                                  .put("id2", "test message two")
+    *                                  .build());
+    * 
+    * if (results.keySet().equals(ImmutableSet.of("id", "id2"))
+    *    // all ok
+    * else
+    *   results.getErrors();
+    * </pre>
+    * 
+    * @param idMessageBody
+    *           id for correlating the result to message body
+    * 
+    * @return result that contains success or errors of the operation
+    * @see #send(String)
+    */
+   BatchResult<? extends MessageIdAndMD5> send(Map<String, String> idMessageBody);
+
+   /**
+    * Same as {@link #send(Map)}, except that we generate numeric ids starting
+    * with {@code 1}
+    * 
+    * @param messageBodies
+    *           message bodies to send
+    * @see #send(Map)
+    */
+   BatchResult<? extends MessageIdAndMD5> send(Iterable<String> messageBodies);
+
+   /**
+    * same as {@link #sendMessage(URI, String)} except you can control options
+    * such as delay seconds.
+    * 
+    * @param options
+    *           options such as delay seconds
+    * @see #sendMessage(URI, String)
+    */
+   MessageIdAndMD5 send(String message, SendMessageOptions options);
+
+   /**
+    * The ReceiveMessage action retrieves one or more messages from the
+    * specified queue. The ReceiveMessage action does not delete the message
+    * after it is retrieved. To delete a message, you must use the DeleteMessage
+    * action. For more information about message deletion in the message life
+    * cycle, see Message Lifecycle.
+    * 
+    * <h4>Note</h4>
+    * 
+    * Due to the distributed nature of the queue, a weighted random set of
+    * machines is sampled on a ReceiveMessage call. That means only the messages
+    * on the sampled machines are returned. If the number of messages in the
+    * queue is small (less than 1000), it is likely you will get fewer messages
+    * than you requested per ReceiveMessage call. If the number of messages in
+    * the queue is extremely small, you might not receive any messages in a
+    * particular ReceiveMessage response; in which case you should repeat the
+    * request.
+    * 
+    * @param queue
+    *           from where you are receiving messages
+    * @return message including the receipt handle you can use to delete it
+    */
+   Message receive();
+
+   /**
+    * same as {@link #receive(URI)} except you can provide options like
+    * VisibilityTimeout parameter in your request, which will be applied to the
+    * messages that SQS returns in the response. If you do not include the
+    * parameter, the overall visibility timeout for the queue is used for the
+    * returned messages.
+    * 
+    * @param options
+    *           options such as VisibilityTimeout
+    * @see #receive(URI)
+    */
+   Message receive(ReceiveMessageOptions options);
+
+   /**
+    * same as {@link #receive(URI)} except you can receive multiple messages.
+    * 
+    * @param max
+    *           maximum messages to receive, current limit is 10
+    * @see #receive(URI)
+    */
+   FluentIterable<Message> receive(int max);
+
+   /**
+    * same as {@link #receive(URI, int)} except you can provide options like
+    * VisibilityTimeout parameter in your request, which will be applied to the
+    * messages that SQS returns in the response. If you do not include the
+    * parameter, the overall visibility timeout for the queue is used for the
+    * returned messages.
+    * 
+    * @param options
+    *           options such as VisibilityTimeout
+    * @see #receive(URI, int)
+    */
+   FluentIterable<Message> receive(int max, ReceiveMessageOptions options);
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/features/MessageAsyncApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/features/MessageAsyncApi.java
new file mode 100644
index 0000000..6438e7b
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/features/MessageAsyncApi.java
@@ -0,0 +1,275 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static org.jclouds.sqs.reference.SQSParameters.ACTION;
+import static org.jclouds.sqs.reference.SQSParameters.VERSION;
+
+import java.util.Map;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+import org.jclouds.Constants;
+import org.jclouds.aws.filters.FormSigner;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.VirtualHost;
+import org.jclouds.rest.annotations.XMLResponseParser;
+import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
+import org.jclouds.sqs.binders.BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams;
+import org.jclouds.sqs.binders.BindDeleteMessageBatchRequestEntryToIndexedFormParams;
+import org.jclouds.sqs.binders.BindSendMessageBatchRequestEntryToIndexedFormParams;
+import org.jclouds.sqs.binders.BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams;
+import org.jclouds.sqs.domain.BatchResult;
+import org.jclouds.sqs.domain.Message;
+import org.jclouds.sqs.domain.MessageIdAndMD5;
+import org.jclouds.sqs.options.ReceiveMessageOptions;
+import org.jclouds.sqs.options.SendMessageOptions;
+import org.jclouds.sqs.xml.ChangeMessageVisibilityBatchResponseHandler;
+import org.jclouds.sqs.xml.DeleteMessageBatchResponseHandler;
+import org.jclouds.sqs.xml.MessageHandler;
+import org.jclouds.sqs.xml.ReceiveMessageResponseHandler;
+import org.jclouds.sqs.xml.RegexMessageIdAndMD5Handler;
+import org.jclouds.sqs.xml.SendMessageBatchResponseHandler;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Table;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides access to SQS via their REST API.
+ * <p/>
+ * 
+ * @author Adrian Cole
+ */
+@RequestFilters(FormSigner.class)
+@FormParams(keys = VERSION, values = "{" + Constants.PROPERTY_API_VERSION + "}")
+@VirtualHost
+public interface MessageAsyncApi {
+
+   /**
+    * @see MessageApi#delete(String)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DeleteMessage")
+   @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
+   ListenableFuture<Void> delete(@FormParam("ReceiptHandle") String receiptHandle);
+
+   /**
+    * @see MessageApi#delete(Map)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DeleteMessageBatch")
+   @XMLResponseParser(DeleteMessageBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<String>> delete(
+         @BinderParam(BindDeleteMessageBatchRequestEntryToIndexedFormParams.class) Map<String, String> idReceiptHandle);
+
+   /**
+    * @see MessageApi#delete(Iterable)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DeleteMessageBatch")
+   @XMLResponseParser(DeleteMessageBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<String>> delete(
+         @BinderParam(BindDeleteMessageBatchRequestEntryToIndexedFormParams.class) Iterable<String> receiptHandles);
+
+   /**
+    * @see MessageApi#changeVisibility(String, int)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ChangeMessageVisibility")
+   ListenableFuture<Void> changeVisibility(@FormParam("ReceiptHandle") String receiptHandle,
+         @FormParam("VisibilityTimeout") int visibilityTimeout);
+
+   /**
+    * @see MessageApi#changeVisibility(Table)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ChangeMessageVisibilityBatch")
+   @XMLResponseParser(ChangeMessageVisibilityBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<String>> changeVisibility(
+         @BinderParam(BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams.class) Table<String, String, Integer> idReceiptHandleVisibilityTimeout);
+
+   /**
+    * @see MessageApi#changeVisibility(Map)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ChangeMessageVisibilityBatch")
+   @XMLResponseParser(ChangeMessageVisibilityBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<String>> changeVisibility(
+         @BinderParam(BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams.class) Map<String, Integer> receiptHandleVisibilityTimeout);
+
+   /**
+    * @see MessageApi#changeVisibility(Map, int)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ChangeMessageVisibilityBatch")
+   @MapBinder(BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams.class)
+   @XMLResponseParser(ChangeMessageVisibilityBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<String>> changeVisibility(
+         @PayloadParam("idReceiptHandle") Map<String, String> idReceiptHandle,
+         @PayloadParam("visibilityTimeout") int visibilityTimeout);
+
+   /**
+    * @see MessageApi#changeVisibility(Iterable, int)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ChangeMessageVisibilityBatch")
+   @MapBinder(BindChangeMessageVisibilityBatchRequestEntryToIndexedFormParams.class)
+   @XMLResponseParser(ChangeMessageVisibilityBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<String>> changeVisibility(
+         @PayloadParam("receiptHandles") Iterable<String> receiptHandles,
+         @PayloadParam("visibilityTimeout") int visibilityTimeout);
+
+   /**
+    * @see MessageApi#send(String)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SendMessage")
+   @ResponseParser(RegexMessageIdAndMD5Handler.class)
+   ListenableFuture<? extends MessageIdAndMD5> send(@FormParam("MessageBody") String message);
+
+   /**
+    * @see MessageApi#send(String, SendMessageOptions)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SendMessage")
+   @ResponseParser(RegexMessageIdAndMD5Handler.class)
+   ListenableFuture<? extends MessageIdAndMD5> send(@FormParam("MessageBody") String message, SendMessageOptions options);
+
+   /**
+    * @see MessageApi#sendWithDelays(Table)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SendMessageBatch")
+   @ResponseParser(RegexMessageIdAndMD5Handler.class)
+   @XMLResponseParser(SendMessageBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<? extends MessageIdAndMD5>> sendWithDelays(
+         @BinderParam(BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams.class) Table<String, String, Integer> idMessageBodyDelaySeconds);
+
+   /**
+    * @see MessageApi#sendWithDelays(Map)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SendMessageBatch")
+   @ResponseParser(RegexMessageIdAndMD5Handler.class)
+   @XMLResponseParser(SendMessageBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<? extends MessageIdAndMD5>> sendWithDelays(
+         @BinderParam(BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams.class) Map<String, Integer> messageBodyDelaySeconds);
+
+   /**
+    * @see MessageApi#sendWithDelay(Map, int)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SendMessageBatch")
+   @MapBinder(BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams.class)
+   @XMLResponseParser(SendMessageBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<? extends MessageIdAndMD5>> sendWithDelay(
+         @PayloadParam("idMessageBody") Map<String, String> idMessageBody,
+         @PayloadParam("delaySeconds") int delaySeconds);
+
+   /**
+    * @see MessageApi#sendWithDelay(Iterable, int)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SendMessageBatch")
+   @MapBinder(BindSendMessageBatchRequestEntryWithDelaysToIndexedFormParams.class)
+   @XMLResponseParser(SendMessageBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<? extends MessageIdAndMD5>> sendWithDelay(
+         @PayloadParam("messageBodies") Iterable<String> messageBodies, @PayloadParam("delaySeconds") int delaySeconds);
+
+   /**
+    * @see MessageApi#send(Map)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SendMessageBatch")
+   @XMLResponseParser(SendMessageBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<? extends MessageIdAndMD5>> send(
+         @BinderParam(BindSendMessageBatchRequestEntryToIndexedFormParams.class) Map<String, String> idMessageBody);
+
+   /**
+    * @see MessageApi#send(Iterable)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SendMessageBatch")
+   @XMLResponseParser(SendMessageBatchResponseHandler.class)
+   ListenableFuture<? extends BatchResult<? extends MessageIdAndMD5>> send(
+         @BinderParam(BindSendMessageBatchRequestEntryToIndexedFormParams.class) Iterable<String> messageBodies);
+
+   /**
+    * @see MessageApi#receive()
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ReceiveMessage")
+   @XMLResponseParser(MessageHandler.class)
+   ListenableFuture<Message> receive();
+
+   /**
+    * @see MessageApi#receive(ReceiveMessageOptions)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ReceiveMessage")
+   @XMLResponseParser(MessageHandler.class)
+   ListenableFuture<? extends Message> receive(ReceiveMessageOptions options);
+
+   /**
+    * @see MessageApi#receive(int)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ReceiveMessage")
+   @XMLResponseParser(ReceiveMessageResponseHandler.class)
+   ListenableFuture<? extends FluentIterable<? extends Message>> receive(@FormParam("MaxNumberOfMessages") int max);
+
+   /**
+    * @see MessageApi#receive(int, ReceiveMessageOptions)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ReceiveMessage")
+   @XMLResponseParser(ReceiveMessageResponseHandler.class)
+   ListenableFuture<? extends FluentIterable<? extends Message>> receive(@FormParam("MaxNumberOfMessages") int max,
+         ReceiveMessageOptions options);
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/features/PermissionApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/features/PermissionApi.java
new file mode 100644
index 0000000..2f2498e
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/features/PermissionApi.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.sqs.domain.Action;
+
+/**
+ * Provides access to SQS via their REST API.
+ * <p/>
+ * 
+ * @see PermissionAsyncApi
+ * @author Adrian Cole
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface PermissionApi {
+
+   /**
+    * The AddPermission action adds a permission to a queue for a specific
+    * principal. This allows for sharing access to the queue.
+    * 
+    * When you create a queue, you have full control access rights for the
+    * queue. Only you (as owner of the queue) can grant or deny permissions to
+    * the queue. For more information about these permissions, see Shared Queues
+    * in the Amazon SQS Developer Guide.
+    * 
+    * Note
+    * 
+    * AddPermission writes an SQS-generated policy. If you want to write your
+    * own policy, use SetQueueAttributes to upload your policy.
+    * 
+    * @param queue
+    *           queue to change permissions on
+    * @param label
+    * 
+    *           The unique identification of the permission you're setting.
+    *           example: AliceSendMessage
+    * 
+    *           Constraints: Maximum 80 characters; alphanumeric characters,
+    *           hyphens (-), and underscores (_) are allowed.
+    * @param permission
+    *           The action you want to allow for the specified principal.
+    * @param accountId
+    *           The AWS account number of the principal who will be given
+    *           permission. The principal must have an AWS account, but does not
+    *           need to be signed up for Amazon SQS. For information about
+    *           locating the AWS account identification, see Your AWS
+    *           Identifiers in the Amazon SQS Developer Guide.
+    * 
+    *           Constraints: Valid 12-digit AWS account number, without hyphens
+    * 
+    */
+   void addPermissionToAccount(String label, Action permission, String accountId);
+
+   /**
+    * The RemovePermission action revokes any permissions in the queue policy
+    * that matches the Label parameter. Only the owner of the queue can remove
+    * permissions.
+    * 
+    * @param queue
+    *           queue to change permissions on
+    * 
+    * @param label
+    *           The identification of the permission you want to remove. This is
+    *           the label you added in AddPermission. example: AliceSendMessage
+    */
+   void remove(String label);
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/features/PermissionAsyncApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/features/PermissionAsyncApi.java
new file mode 100644
index 0000000..54902bd
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/features/PermissionAsyncApi.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static org.jclouds.sqs.reference.SQSParameters.ACTION;
+import static org.jclouds.sqs.reference.SQSParameters.VERSION;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+import org.jclouds.Constants;
+import org.jclouds.aws.filters.FormSigner;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.VirtualHost;
+import org.jclouds.sqs.domain.Action;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides access to SQS via their REST API.
+ * <p/>
+ * 
+ * @author Adrian Cole
+ */
+@RequestFilters(FormSigner.class)
+@FormParams(keys = VERSION, values = "{" + Constants.PROPERTY_API_VERSION + "}")
+@VirtualHost
+public interface PermissionAsyncApi {
+
+   /**
+    * @see PermissionApi#addPermissionToAccount
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "AddPermission")
+   ListenableFuture<Void> addPermissionToAccount(@FormParam("Label") String label,
+         @FormParam("ActionName.1") Action permission, @FormParam("AWSAccountId.1") String accountId);
+
+   /**
+    * @see PermissionApi#remove
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "RemovePermission")
+   ListenableFuture<Void> remove(@FormParam("Label") String label);
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueApi.java
new file mode 100644
index 0000000..7f208bf
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueApi.java
@@ -0,0 +1,213 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.sqs.domain.QueueAttributes;
+import org.jclouds.sqs.options.CreateQueueOptions;
+import org.jclouds.sqs.options.ListQueuesOptions;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * Provides access to SQS via their REST API.
+ * <p/>
+ * 
+ * @see QueueAsyncApi
+ * @author Adrian Cole
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface QueueApi {
+
+   /**
+    * The ListQueues action returns a list of your queues. The maximum number of
+    * queues that can be returned is 1000. If you specify a value for the
+    * optional QueueNamePrefix parameter, only queues with a name beginning with
+    * the specified value are returned
+    * 
+    * @param region
+    *           Queues are Region-specific.
+    * @param options
+    *           specify prefix or other options
+    * 
+    * @see <a href=
+    *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryListQueues.html"
+    *      />
+    */
+   FluentIterable<URI> list();
+
+   FluentIterable<URI> list(ListQueuesOptions options);
+
+   /**
+    * The CreateQueue action creates a new queue.
+    * 
+    * When you request CreateQueue, you provide a name for the queue. To
+    * successfully create a new queue, you must provide a name that is unique
+    * within the scope of your own queues.
+    * 
+    * <h4>Note</h4>
+    * 
+    * If you delete a queue, you must wait at least 60 seconds before creating a
+    * queue with the same name.
+    * 
+    * If you provide the name of an existing queue, along with the exact names
+    * and values of all the queue's attributes, CreateQueue returns the queue
+    * URL for the existing queue. If the queue name, attribute names, or
+    * attribute values do not match an existing queue, CreateQueue returns an
+    * error.
+    * 
+    * <h4>Tip</h4>
+    * 
+    * Use GetQueueUrl to get a queue's URL. GetQueueUrl requires only the
+    * QueueName parameter.
+    * 
+    * @param region
+    *           Queues are Region-specific.
+    * @param queueName
+    *           The name to use for the queue created. Constraints: Maximum 80
+    *           characters; alphanumeric characters, hyphens (-), and
+    *           underscores (_) are allowed.
+    */
+   // this will gracefully attempt to resolve name issues
+   @Timeout(duration = 61, timeUnit = TimeUnit.SECONDS)
+   URI create(String queueName);
+
+   /**
+    * same as {@link #create(String, String)} except you can
+    * control options such as delay seconds.
+    * 
+    * @param options
+    *           options such as delay seconds
+    * @see #create(String, String)
+    */
+   @Timeout(duration = 61, timeUnit = TimeUnit.SECONDS)
+   URI create(String queueName, CreateQueueOptions options);
+
+   /**
+    * The DeleteQueue action deletes the queue specified by the queue URL,
+    * regardless of whether the queue is empty. If the specified queue does not
+    * exist, SQS returns a successful response.
+    * 
+    * <h4>Caution</h4>
+    * 
+    * Use DeleteQueue with care; once you delete your queue, any messages in the
+    * queue are no longer available.
+    * 
+    * When you delete a queue, the deletion process takes up to 60 seconds.
+    * Requests you send involving that queue during the 60 seconds might
+    * succeed. For example, a SendMessage request might succeed, but after the
+    * 60 seconds, the queue and that message you sent no longer exist. Also,
+    * when you delete a queue, you must wait at least 60 seconds before creating
+    * a queue with the same name.
+    * 
+    * We reserve the right to delete queues that have had no activity for more
+    * than 30 days. For more information, see About SQS Queues in the Amazon SQS
+    * Developer Guide.
+    * 
+    * @param queue
+    *           queue you want to delete
+    */
+   void delete(URI queue);
+
+   /**
+    * returns all attributes of a queue.
+    * 
+    * @param queue
+    *           queue to get the attributes of
+    */
+   QueueAttributes getAttributes(URI queue);
+
+   /**
+    * The SetQueueAttributes action sets one attribute of a queue per request.
+    * When you change a queue's attributes, the change can take up to 60 seconds
+    * to propagate throughout the SQS system.
+    * 
+    * @param queue
+    *           queue to set the attribute on
+    * @param name
+    * 
+    *           The name of the attribute you want to set.
+    * 
+    *           VisibilityTimeout - The length of time (in seconds) that a
+    *           message received from a queue will be invisible to other
+    *           receiving components when they ask to receive messages. For more
+    *           information about VisibilityTimeout, see Visibility Timeout in
+    *           the Amazon SQS Developer Guide.
+    * 
+    *           Policy - The formal description of the permissions for a
+    *           resource. For more information about Policy, see Basic Policy
+    *           Structure in the Amazon SQS Developer Guide.
+    * 
+    *           MaximumMessageSize - The limit of how many bytes a message can
+    *           contain before Amazon SQS rejects it.
+    * 
+    *           MessageRetentionPeriod - The number of seconds Amazon SQS
+    *           retains a message.
+    * 
+    *           DelaySeconds - The time in seconds that the delivery of all
+    *           messages in the queue will be delayed.
+    * @param value
+    *           The value of the attribute you want to set. To delete a queue's
+    *           access control policy, set the policy to "".
+    * 
+    *           Constraints: Constraints are specific for each value.
+    * 
+    *           VisibilityTimeout - An integer from 0 to 43200 (12 hours). The
+    *           default for this attribute is 30 seconds.
+    * 
+    *           Policy - A valid form-url-encoded policy. For more information
+    *           about policy structure, see Basic Policy Structure in the Amazon
+    *           SQS Developer Guide. For more information about
+    *           form-url-encoding, see
+    *           http://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2.1.
+    * 
+    *           MaximumMessageSize - An integer from 1024 bytes (1 KiB) up to
+    *           65536 bytes (64 KiB). The default for this attribute is 65536
+    *           (64 KiB).
+    * 
+    *           MessageRetentionPeriod - Integer representing seconds, from 60
+    *           (1 minute) to 1209600 (14 days). The default for this attribute
+    *           is 345600 (4 days).
+    * 
+    *           DelaySeconds - An integer from 0 to 900 (15 minutes). The
+    *           default for this attribute is 0.
+    */
+   void setAttribute(URI queue, String name, String value);
+
+   /**
+    * returns some attributes of a queue.
+    * 
+    * @param queue
+    *           queue to get the attributes of
+    */
+   Map<String, String> getAttributes(URI queue, Iterable<String> attributeNames);
+
+   /**
+    * returns an attribute of a queue.
+    * 
+    * @param queue
+    *           queue to get the attributes of
+    */
+   String getAttribute(URI queue, String attributeName);
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueAsyncApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueAsyncApi.java
new file mode 100644
index 0000000..c0a8390
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueAsyncApi.java
@@ -0,0 +1,152 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static org.jclouds.sqs.reference.SQSParameters.ACTION;
+import static org.jclouds.sqs.reference.SQSParameters.VERSION;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+import org.jclouds.Constants;
+import org.jclouds.aws.filters.FormSigner;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.EndpointParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.annotations.VirtualHost;
+import org.jclouds.rest.annotations.XMLResponseParser;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
+import org.jclouds.sqs.binders.BindAttributeNamesToIndexedFormParams;
+import org.jclouds.sqs.domain.QueueAttributes;
+import org.jclouds.sqs.functions.MapToQueueAttributes;
+import org.jclouds.sqs.options.CreateQueueOptions;
+import org.jclouds.sqs.options.ListQueuesOptions;
+import org.jclouds.sqs.xml.AttributesHandler;
+import org.jclouds.sqs.xml.RegexListQueuesResponseHandler;
+import org.jclouds.sqs.xml.RegexQueueHandler;
+import org.jclouds.sqs.xml.ValueHandler;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides access to SQS via their REST API.
+ * <p/>
+ * 
+ * @author Adrian Cole
+ */
+@RequestFilters(FormSigner.class)
+@FormParams(keys = VERSION, values = "{" + Constants.PROPERTY_API_VERSION + "}")
+@VirtualHost
+public interface QueueAsyncApi {
+
+   /**
+    * @see QueueApi#list
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ListQueues")
+   @ResponseParser(RegexListQueuesResponseHandler.class)
+   ListenableFuture<FluentIterable<URI>> list();
+
+   /**
+    * @see QueueApi#list(ListQueuesOptions)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "ListQueues")
+   @ResponseParser(RegexListQueuesResponseHandler.class)
+   ListenableFuture<FluentIterable<URI>> list(ListQueuesOptions options);
+
+   /**
+    * @see QueueApi#create
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "CreateQueue")
+   @ResponseParser(RegexQueueHandler.class)
+   ListenableFuture<URI> create(@FormParam("QueueName") String queueName);
+
+   /**
+    * @see QueueApi#create
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "CreateQueue")
+   @ResponseParser(RegexQueueHandler.class)
+   ListenableFuture<URI> create(@FormParam("QueueName") String queueName, CreateQueueOptions options);
+
+   /**
+    * @see QueueApi#delete
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "DeleteQueue")
+   @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
+   ListenableFuture<Void> delete(@EndpointParam URI queue);
+
+   /**
+    * @see QueueApi#getAttributes(URI)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = { ACTION, "AttributeName.1" }, values = { "GetQueueAttributes", "All" })
+   @Transform(MapToQueueAttributes.class)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @XMLResponseParser(AttributesHandler.class)
+   ListenableFuture<? extends QueueAttributes> getAttributes(@EndpointParam URI queue);
+
+   /**
+    * @see QueueApi#getAttributes(URI, Iterable)
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "GetQueueAttributes")
+   @XMLResponseParser(AttributesHandler.class)
+   ListenableFuture<Map<String, String>> getAttributes(@EndpointParam URI queue,
+         @BinderParam(BindAttributeNamesToIndexedFormParams.class) Iterable<String> attributeNames);
+
+   /**
+    * @see QueueApi#getAttribute
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "GetQueueAttributes")
+   @XMLResponseParser(ValueHandler.class)
+   ListenableFuture<String> getAttribute(@EndpointParam URI queue, @FormParam("AttributeName.1") String attributeName);
+
+   /**
+    * @see QueueApi#setAttribute
+    */
+   @POST
+   @Path("/")
+   @FormParams(keys = ACTION, values = "SetQueueAttributes")
+   ListenableFuture<Void> setAttribute(@EndpointParam URI queue, @FormParam("Attribute.Name") String name,
+         @FormParam("Attribute.Value") String value);
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/functions/MapToQueueAttributes.java b/apis/sqs/src/main/java/org/jclouds/sqs/functions/MapToQueueAttributes.java
new file mode 100644
index 0000000..1728beb
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/functions/MapToQueueAttributes.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.functions;
+
+import java.util.Date;
+import java.util.Map;
+
+import org.jclouds.sqs.domain.Attribute;
+import org.jclouds.sqs.domain.QueueAttributes;
+import org.jclouds.sqs.domain.QueueAttributes.Builder;
+
+import com.google.common.base.Function;
+
+/**
+ * Converts a Map to a typed QueueAttributes object
+ * 
+ * @author Adrian Cole
+ */
+public class MapToQueueAttributes implements Function<Map<String, String>, QueueAttributes> {
+
+   @Override
+   public QueueAttributes apply(Map<String, String> input) {
+      if (input == null)
+         return null;
+      Builder<?> builder = QueueAttributes.builder();
+      builder.queueArn(input.get(Attribute.QUEUE_ARN));
+      builder.approximateNumberOfMessages(Long.parseLong(input.get(Attribute.APPROXIMATE_NUMBER_OF_MESSAGES)));
+      builder.approximateNumberOfMessagesNotVisible(Long.parseLong(input
+            .get(Attribute.APPROXIMATE_NUMBER_OF_MESSAGES_NOT_VISIBLE)));
+      builder.approximateNumberOfMessagesDelayed(Long.parseLong(input
+            .get(Attribute.APPROXIMATE_NUMBER_OF_MESSAGES_DELAYED)));
+      builder.visibilityTimeout(Integer.parseInt(input.get(Attribute.VISIBILITY_TIMEOUT)));
+      builder.createdTimestamp(new Date(Long.parseLong(input.get(Attribute.CREATED_TIMESTAMP))));
+      builder.lastModifiedTimestamp(new Date(Long.parseLong(input.get(Attribute.LAST_MODIFIED_TIMESTAMP))));
+      builder.rawPolicy(input.get(Attribute.POLICY));
+      builder.maximumMessageSize(Integer.parseInt(input.get(Attribute.MAXIMUM_MESSAGE_SIZE)));
+      builder.messageRetentionPeriod(Integer.parseInt(input.get(Attribute.MESSAGE_RETENTION_PERIOD)));
+      builder.delaySeconds(Integer.parseInt(input.get(Attribute.DELAY_SECONDS)));
+      return builder.build();
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/handlers/ParseSQSErrorFromXmlContent.java b/apis/sqs/src/main/java/org/jclouds/sqs/handlers/ParseSQSErrorFromXmlContent.java
new file mode 100644
index 0000000..3eb4d29
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/handlers/ParseSQSErrorFromXmlContent.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.handlers;
+
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.aws.domain.AWSError;
+import org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent;
+import org.jclouds.aws.util.AWSUtils;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * @author Adrian Cole
+ * 
+ */
+@Singleton
+public class ParseSQSErrorFromXmlContent extends ParseAWSErrorFromXmlContent {
+   protected Set<String> resourceNotFoundCodes = ImmutableSet.of("AWS.SimpleQueueService.NonExistentQueue");
+   protected Set<String> illegalStateCodes = ImmutableSet.of("AWS.SimpleQueueService.QueueDeletedRecently",
+         "AWS.SimpleQueueService.QueueNameExists");
+   protected Set<String> illegalArgumentCodes = ImmutableSet.of("InvalidAttributeName", "ReadCountOutOfRange",
+         "InvalidMessageContents", "MessageTooLong");
+
+   @Inject
+   public ParseSQSErrorFromXmlContent(AWSUtils utils) {
+      super(utils);
+   }
+
+   @Override
+   protected Exception refineException(HttpCommand command, HttpResponse response, Exception exception, AWSError error,
+         String message) {
+      String errorCode = (error != null && error.getCode() != null) ? error.getCode() : null;
+      if (resourceNotFoundCodes.contains(errorCode))
+         exception = new ResourceNotFoundException(message, exception);
+      else if (illegalStateCodes.contains(errorCode))
+         exception = new IllegalStateException(message, exception);
+      else if (illegalArgumentCodes.contains(errorCode))
+         exception = new IllegalArgumentException(message, exception);
+      else
+         exception = super.refineException(command, response, exception, error, message);
+      return exception;
+   }
+}
\ No newline at end of file
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/handlers/SQSErrorRetryHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/handlers/SQSErrorRetryHandler.java
new file mode 100644
index 0000000..7af1680
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/handlers/SQSErrorRetryHandler.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.handlers;
+
+import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_MAX_RETRIES;
+import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_RETRY_INTERVAL;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Named;
+
+import org.jclouds.aws.domain.AWSError;
+import org.jclouds.aws.handlers.AWSClientErrorRetryHandler;
+import org.jclouds.aws.util.AWSUtils;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.util.concurrent.Uninterruptibles;
+import com.google.inject.Inject;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+public class SQSErrorRetryHandler extends AWSClientErrorRetryHandler {
+
+   private final long retryInterval;
+   private final int maxTries;
+
+   @Inject
+   public SQSErrorRetryHandler(AWSUtils utils, BackoffLimitedRetryHandler backoffLimitedRetryHandler,
+         @ClientError Set<String> retryableCodes, @Named(CREATE_QUEUE_MAX_RETRIES) int maxTries,
+         @Named(CREATE_QUEUE_RETRY_INTERVAL) long retryInterval) {
+      super(utils, backoffLimitedRetryHandler, retryableCodes);
+      this.maxTries = maxTries;
+      this.retryInterval = retryInterval;
+   }
+
+   @VisibleForTesting
+   public boolean shouldRetryRequestOnError(HttpCommand command, HttpResponse response, AWSError error) {
+      if ("AWS.SimpleQueueService.QueueDeletedRecently".equals(error.getCode())) {
+         if (command.incrementFailureCount() - 1 < maxTries) {
+            Uninterruptibles.sleepUninterruptibly(retryInterval, TimeUnit.MILLISECONDS);
+            return true;
+         }
+         return false;
+      }
+      return super.shouldRetryRequestOnError(command, response, error);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/options/CreateQueueOptions.java b/apis/sqs/src/main/java/org/jclouds/sqs/options/CreateQueueOptions.java
new file mode 100644
index 0000000..7cd0694
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/options/CreateQueueOptions.java
@@ -0,0 +1,148 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.options;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimap;
+
+/**
+ * Options used to receive a message from a queue.
+ * 
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryCreateQueue.html"
+ *      >docs</a>
+ * 
+ * @author Adrian Cole
+ */
+public class CreateQueueOptions extends BaseHttpRequestOptions implements Cloneable {
+
+   private ImmutableMap.Builder<String, String> attributes = ImmutableMap.<String, String> builder();
+
+   /**
+    * The duration (in seconds) that the received messages are hidden from
+    * subsequent retrieve requests after being retrieved by a CreateQueue
+    * request.
+    * 
+    * @param visibilityTimeout
+    *           Constraints: 0 to 43200 (maximum 12 hours)
+    * 
+    *           Default: The visibility timeout for the queue
+    */
+   public CreateQueueOptions visibilityTimeout(int visibilityTimeout) {
+      return attribute("VisibilityTimeout", visibilityTimeout + "");
+   }
+
+   /**
+    */
+   public CreateQueueOptions attributes(Map<String, String> attributes) {
+      this.attributes = ImmutableMap.<String, String> builder().putAll(attributes);
+      return this;
+   }
+
+   /**
+    * @see #attributes
+    */
+   public CreateQueueOptions attribute(String name, String value) {
+      this.attributes.put(name, value);
+      return this;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see CreateQueueOptions#visibilityTimeout
+       */
+      public static CreateQueueOptions visibilityTimeout(Integer visibilityTimeout) {
+         return new CreateQueueOptions().visibilityTimeout(visibilityTimeout);
+      }
+
+      /**
+       * @see CreateQueueOptions#attribute
+       */
+      public static CreateQueueOptions attribute(String name, String value) {
+         return new CreateQueueOptions().attribute(name, value);
+      }
+
+      /**
+       * @see CreateQueueOptions#attributes
+       */
+      public static CreateQueueOptions attributes(Map<String, String> attributes) {
+         return new CreateQueueOptions().attributes(attributes);
+      }
+   }
+
+   @Override
+   public Multimap<String, String> buildFormParameters() {
+      Multimap<String, String> params = super.buildFormParameters();
+      ImmutableMap<String, String> attributes = this.attributes.build();
+      if (attributes.size() > 0) {
+         int nameIndex = 1;
+         for (Entry<String, String> attribute : attributes.entrySet()) {
+            params.put("Attribute." + nameIndex + ".Name", attribute.getKey());
+            params.put("Attribute." + nameIndex + ".Value", attribute.getValue());
+            nameIndex++;
+         }
+      }
+      return params;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(attributes);
+   }
+
+   @Override
+   public CreateQueueOptions clone() {
+      return new CreateQueueOptions().attributes(attributes.build());
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      CreateQueueOptions other = CreateQueueOptions.class.cast(obj);
+      return Objects.equal(this.attributes, other.attributes);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      ImmutableMap<String, String> attributes = this.attributes.build();
+      return Objects.toStringHelper(this).omitNullValues().add("attributes", attributes.size() > 0 ? attributes : null)
+            .toString();
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/options/ListQueuesOptions.java b/apis/sqs/src/main/java/org/jclouds/sqs/options/ListQueuesOptions.java
new file mode 100644
index 0000000..851c61f
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/options/ListQueuesOptions.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Contains options supported in the Form API for the ListQueues operation. <h2>
+ * Usage</h2> The recommended way to instantiate a ListQueuesOptions object is to statically import
+ * ListQueuesOptions.Builder.* and invoke a static creation method followed by an instance mutator
+ * (if needed):
+ * <p/>
+ * <code>
+ * import static org.jclouds.sqs.options.ListQueuesOptions.Builder.*
+ * <p/>
+ * SQSApi connection = // get connection
+ * Set<Queue> queues = connection.listQueuesInRegion(queuePrefix("foo"));
+ * <code>
+ * 
+ * @author Adrian Cole
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
+ *      />
+ */
+public class ListQueuesOptions extends BaseHttpRequestOptions {
+
+   /**
+    * String to use for filtering the list results. Only those queues whose name begins with the
+    * specified string are returned.
+    * 
+    * @param prefix
+    *           Maximum 80 characters; alphanumeric characters, hyphens (-), and underscores (_) are
+    *           allowed.
+    */
+   public ListQueuesOptions queuePrefix(String prefix) {
+      formParameters.put("QueueNamePrefix", prefix);
+      return this;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see ListQueuesOptions#queuePrefix(String )
+       */
+      public static ListQueuesOptions queuePrefix(String prefix) {
+         ListQueuesOptions options = new ListQueuesOptions();
+         return options.queuePrefix(prefix);
+      }
+
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/options/ReceiveMessageOptions.java b/apis/sqs/src/main/java/org/jclouds/sqs/options/ReceiveMessageOptions.java
new file mode 100644
index 0000000..dcbd6ba
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/options/ReceiveMessageOptions.java
@@ -0,0 +1,164 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+
+/**
+ * Options used to receive a message from a queue.
+ * 
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryReceiveMessage.html"
+ *      >docs</a>
+ * 
+ * @author Adrian Cole
+ */
+public class ReceiveMessageOptions extends BaseHttpRequestOptions implements Cloneable {
+
+   private Integer visibilityTimeout;
+   private ImmutableSet.Builder<String> attributes = ImmutableSet.<String> builder();
+
+   /**
+    * The duration (in seconds) that the received messages are hidden from
+    * subsequent retrieve requests after being retrieved by a ReceiveMessage
+    * request.
+    * 
+    * @param visibilityTimeout
+    *           Constraints: 0 to 43200 (maximum 12 hours)
+    * 
+    *           Default: The visibility timeout for the queue
+    */
+   public ReceiveMessageOptions visibilityTimeout(Integer visibilityTimeout) {
+      this.visibilityTimeout = visibilityTimeout;
+      return this;
+   }
+
+   /**
+    * The attribute you want to get.
+    * 
+    * All - returns all values.
+    * 
+    * SenderId - returns the AWS account number (or the IP address, if anonymous
+    * access is allowed) of the sender.
+    * 
+    * SentTimestamp - returns the time when the message was sent (epoch time in
+    * milliseconds).
+    * 
+    * ApproximateReceiveCount - returns the number of times a message has been
+    * received but not deleted.
+    * 
+    * ApproximateFirstReceiveTimestamp - returns the time when the message was
+    * first received (epoch time in milliseconds).
+    */
+   public ReceiveMessageOptions attributes(Iterable<String> attributes) {
+      this.attributes = ImmutableSet.<String> builder().addAll(attributes);
+      return this;
+   }
+
+   /**
+    * @see #attributes
+    */
+   public ReceiveMessageOptions attribute(String attribute) {
+      this.attributes.add(attribute);
+      return this;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see ReceiveMessageOptions#visibilityTimeout
+       */
+      public static ReceiveMessageOptions visibilityTimeout(Integer visibilityTimeout) {
+         return new ReceiveMessageOptions().visibilityTimeout(visibilityTimeout);
+      }
+
+      /**
+       * @see ReceiveMessageOptions#attribute
+       */
+      public static ReceiveMessageOptions attribute(String attribute) {
+         return new ReceiveMessageOptions().attribute(attribute);
+      }
+
+      /**
+       * @see ReceiveMessageOptions#attributes
+       */
+      public static ReceiveMessageOptions attributes(Iterable<String> attributes) {
+         return new ReceiveMessageOptions().attributes(attributes);
+      }
+   }
+
+   @Override
+   public Multimap<String, String> buildFormParameters() {
+      Multimap<String, String> params = super.buildFormParameters();
+      if (visibilityTimeout != null)
+         params.put("VisibilityTimeout", visibilityTimeout.toString());
+      ImmutableSet<String> attributes = this.attributes.build();
+      if (attributes.size() > 0) {
+         int nameIndex = 1;
+         for (String attribute : attributes) {
+            params.put("AttributeName." + nameIndex, attribute);
+            nameIndex++;
+         }
+      }
+      return params;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(visibilityTimeout, attributes);
+   }
+
+   @Override
+   public ReceiveMessageOptions clone() {
+      return new ReceiveMessageOptions().visibilityTimeout(visibilityTimeout).attributes(attributes.build());
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      ReceiveMessageOptions other = ReceiveMessageOptions.class.cast(obj);
+      return Objects.equal(this.visibilityTimeout, other.visibilityTimeout)
+            && Objects.equal(this.attributes, other.attributes);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      ImmutableSet<String> attributes = this.attributes.build();
+      return Objects.toStringHelper(this).omitNullValues().add("visibilityTimeout", visibilityTimeout)
+            .add("attributes", attributes.size() > 0 ? attributes : null).toString();
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/options/SendMessageOptions.java b/apis/sqs/src/main/java/org/jclouds/sqs/options/SendMessageOptions.java
new file mode 100644
index 0000000..ba17cee
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/options/SendMessageOptions.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Multimap;
+
+/**
+ * Options used to send a message.
+ * 
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QuerySendMessage.html"
+ *      >docs</a>
+ * 
+ * @author Adrian Cole
+ */
+public class SendMessageOptions extends BaseHttpRequestOptions implements Cloneable {
+
+   private Integer delaySeconds;
+
+   /**
+    * The number of seconds to delay a specific message. Messages with a
+    * positive DelaySeconds value become available for processing after the
+    * delay time is finished. If you don't specify a value, the default value
+    * for the queue applies.
+    * 
+    * @param delaySeconds
+    *           from 0 to 900 (15 minutes). If this parameter is not used, the
+    *           default value for the queue applies.
+    */
+   public SendMessageOptions delaySeconds(Integer delaySeconds) {
+      this.delaySeconds = delaySeconds;
+      return this;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see SendMessageOptions#delaySeconds
+       */
+      public static SendMessageOptions delaySeconds(Integer delaySeconds) {
+         return new SendMessageOptions().delaySeconds(delaySeconds);
+      }
+
+   }
+
+   @Override
+   public Multimap<String, String> buildFormParameters() {
+      Multimap<String, String> params = super.buildFormParameters();
+      if (delaySeconds != null)
+         params.put("DelaySeconds", delaySeconds.toString());
+      return params;
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(delaySeconds);
+   }
+
+   @Override
+   public SendMessageOptions clone() {
+      return new SendMessageOptions().delaySeconds(delaySeconds);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      SendMessageOptions other = SendMessageOptions.class.cast(obj);
+      return Objects.equal(this.delaySeconds, other.delaySeconds);
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("delaySeconds", delaySeconds).toString();
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/package-info.java b/apis/sqs/src/main/java/org/jclouds/sqs/package-info.java
new file mode 100644
index 0000000..07b6f72
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/package-info.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * This package contains an Amazon SQS api implemented by {@link org.jclouds.http.HttpCommandExecutorService} commands.
+ *
+ * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/index.html"/>
+ * @author Adrian Cole
+ */
+package org.jclouds.sqs;
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/reference/SQSParameters.java b/apis/sqs/src/main/java/org/jclouds/sqs/reference/SQSParameters.java
new file mode 100644
index 0000000..a50659b
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/reference/SQSParameters.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.reference;
+
+/**
+ * Configuration properties and constants used in SQS connections.
+ * 
+ * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryParams.html"
+ *      />
+ * @author Adrian Cole
+ */
+public interface SQSParameters {
+
+   /**
+    * The action to perform. For example: CreateQueue.
+    */
+   public static final String ACTION = "Action";
+
+   /**
+    * The API version to use, as specified in the WSDL. For example: 2011-10-01.
+    */
+   public static final String VERSION = "Version";
+
+   /**
+    * Your Access Key ID. For example: 0AS7253JW73RRM652K02. For more information, see Your AWS
+    * Identifiers in the Amazon SQS Developer Guide.
+    */
+   public static final String AWS_ACCESS_KEY_ID = "AWSAccessKeyId";
+
+   /**
+    * The date and time the request is signed, in the format YYYY-MM-DDThh:mm:ssZ, as specified in
+    * the ISO 8601 standard. Query requests must include either Timestamp or Expires, but not both.
+    * 
+    */
+   public static final String TIMESTAMP = "Timestamp";
+
+   /**
+    * The date and time at which the signature included in the request expires, in the format
+    * YYYY-MM-DDThh:mm:ssZ, as specified in the ISO 8601 standard. Query requests must include
+    * either Timestamp or Expires, but not both.
+    */
+   public static final String EXPIRES = "Expires";
+   /**
+    * A request signature (for information, see Request Authentication in the Amazon SQS Developer
+    * Guide). For example: Qnpl4Qk/7tINHzfXCiT7VbBatDA=.
+    */
+   public static final String SIGNATURE = "Signature";
+   /**
+    *Required when you use signature version 2 with Query requests. For more information, see Query
+    * Request Authentication in the Amazon SQS Developer Guide.
+    */
+   public static final String SIGNATURE_METHOD = "SignatureMethod";
+   /**
+    * For more information, see Query Request Authentication in the Amazon SQS Developer Guide.
+    */
+   public static final String SIGNATURE_VERSION = "SignatureVersion";
+}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/reference/package-info.java b/apis/sqs/src/main/java/org/jclouds/sqs/reference/package-info.java
similarity index 100%
rename from sandbox-apis/sqs/src/main/java/org/jclouds/sqs/reference/package-info.java
rename to apis/sqs/src/main/java/org/jclouds/sqs/reference/package-info.java
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/AttributesHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/AttributesHandler.java
new file mode 100644
index 0000000..eb9ea4c
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/AttributesHandler.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import java.util.Map;
+
+import org.jclouds.http.functions.ParseSax;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+
+/**
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryGetQueueAttributes.html"
+ *      />
+ * 
+ * @author Adrian Cole
+ */
+public class AttributesHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Map<String, String>> {
+
+   private StringBuilder currentText = new StringBuilder();
+   private Builder<String, String> builder = ImmutableMap.<String, String> builder();
+   private String name;
+
+   @Override
+   public Map<String, String> getResult() {
+      try {
+         return builder.build();
+      } catch (NullPointerException e) {
+         return null;
+      } finally {
+         builder = ImmutableMap.<String, String> builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) {
+      if (qName.equals("Name")) {
+         this.name = currentOrNull(currentText);
+      } else if (qName.equals("Value")) {
+         builder.put(this.name, currentOrNull(currentText));
+         this.name = null;
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/BatchErrorHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/BatchErrorHandler.java
new file mode 100644
index 0000000..24889e2
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/BatchErrorHandler.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.sqs.domain.BatchError;
+
+/**
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryDeleteMessageBatch.html"
+ *      />
+ * 
+ * @author Adrian Cole
+ */
+public class BatchErrorHandler extends ParseSax.HandlerForGeneratedRequestWithResult<BatchError> {
+
+   private StringBuilder currentText = new StringBuilder();
+   private BatchError.Builder builder = BatchError.builder();
+
+   @Override
+   public BatchError getResult() {
+      try {
+         return builder.build();
+      } catch (NullPointerException e) {
+         return null;
+      } finally {
+         builder = BatchError.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) {
+      if (qName.equals("Id")) {
+         builder.id(currentOrNull(currentText));
+      } else if (qName.equals("SenderFault")) {
+         builder.senderFault(Boolean.parseBoolean(currentOrNull(currentText)));
+      } else if (qName.equals("Code")) {
+         builder.code(currentOrNull(currentText));
+      } else if (qName.equals("Message")) {
+         builder.message(currentOrNull(currentText));
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/BatchResponseHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/BatchResponseHandler.java
new file mode 100644
index 0000000..07bd366
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/BatchResponseHandler.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.http.functions.ParseSax.HandlerForGeneratedRequestWithResult;
+import org.jclouds.sqs.domain.BatchError;
+import org.jclouds.sqs.domain.BatchResult;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+/**
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryDeleteMessageBatch.html"
+ *      >docs</a>
+ * 
+ * @author Adrian Cole
+ */
+public class BatchResponseHandler<V> extends ParseSax.HandlerForGeneratedRequestWithResult<BatchResult<V>> {
+
+   private final String resultElement;
+   private final ParseSax.HandlerForGeneratedRequestWithResult<Map.Entry<String, V>> resultHandler;
+   private final BatchErrorHandler errorHandler;
+
+   private ImmutableMap.Builder<String, V> results = ImmutableMap.<String,V> builder();
+   private Builder<BatchError> errors = ImmutableSet.<BatchError> builder();
+
+   private boolean inResult;
+   private boolean inError;
+
+   protected BatchResponseHandler(String resultElement, HandlerForGeneratedRequestWithResult<Map.Entry<String, V>> resultHandler,
+         BatchErrorHandler errorHandler) {
+      this.resultElement = checkNotNull(resultElement, "resultElement");;
+      this.resultHandler = checkNotNull(resultHandler, "resultHandler");;
+      this.errorHandler = checkNotNull(errorHandler, "errorHandler");;
+   }
+
+   @Override
+   public BatchResult<V> getResult() {
+      return BatchResult.<V> builder().putAll(results.build()).errors(errors.build())
+            .build();
+   }
+
+   @Override
+   public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+      if (qName.equals(resultElement)) {
+         inResult = true;
+      } else if (qName.equals("BatchResultErrorEntry")) {
+         inError = true;
+      }
+      if (inResult) {
+         resultHandler.startElement(url, name, qName, attributes);
+      } else if (inError) {
+         errorHandler.startElement(url, name, qName, attributes);
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (qName.equals(resultElement)) {
+         results.put(resultHandler.getResult());
+         inResult = false;
+      } else if (qName.equals("BatchResultErrorEntry")) {
+         errors.add(errorHandler.getResult());
+         inError = false;
+      } else if (inResult) {
+         resultHandler.endElement(uri, name, qName);
+      } else if (inError) {
+         errorHandler.endElement(uri, name, qName);
+      }
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) throws SAXException {
+      if (inResult) {
+         resultHandler.characters(ch, start, length);
+      } else if (inError) {
+         errorHandler.characters(ch, start, length);
+      }
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/ChangeMessageVisibilityBatchResponseHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/ChangeMessageVisibilityBatchResponseHandler.java
new file mode 100644
index 0000000..819f671
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/ChangeMessageVisibilityBatchResponseHandler.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import javax.inject.Inject;
+
+/**
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryChangeMessageVisibilityBatch.html"
+ *      >docs</a>
+ * 
+ * @author Adrian Cole
+ */
+public class ChangeMessageVisibilityBatchResponseHandler extends BatchResponseHandler<String> {
+   @Inject
+   protected ChangeMessageVisibilityBatchResponseHandler(IdHandler resultHandler, BatchErrorHandler errorHandler) {
+      super("ChangeMessageVisibilityBatchResultEntry", resultHandler, errorHandler);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/DeleteMessageBatchResponseHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/DeleteMessageBatchResponseHandler.java
new file mode 100644
index 0000000..1933851
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/DeleteMessageBatchResponseHandler.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import javax.inject.Inject;
+
+/**
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryDeleteMessageBatch.html"
+ *      >docs</a>
+ * 
+ * @author Adrian Cole
+ */
+public class DeleteMessageBatchResponseHandler extends BatchResponseHandler<String> {
+
+   @Inject
+   protected DeleteMessageBatchResponseHandler(IdHandler resultHandler, BatchErrorHandler errorHandler) {
+      super("DeleteMessageBatchResultEntry", resultHandler, errorHandler);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/IdHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/IdHandler.java
new file mode 100644
index 0000000..35d9f42
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/IdHandler.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+/**
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryDeleteMessageBatch.html"
+ *      />
+ * 
+ * @author Adrian Cole
+ */
+public class IdHandler extends TextFromSingleElementHandler<Map.Entry<String, String>> {
+   @Inject
+   protected IdHandler(String elementName) {
+      super("Id");
+   }
+
+   @Override
+   public Map.Entry<String, String> apply(String in) {
+      return Iterables.getOnlyElement(ImmutableMap.of(in, in).entrySet());
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/MessageHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/MessageHandler.java
new file mode 100644
index 0000000..3a972d5
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/MessageHandler.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.sqs.domain.Message;
+
+import com.google.common.hash.HashCodes;
+
+/**
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryReceiveMessage.html"
+ *      />
+ * 
+ * @author Adrian Cole
+ */
+public class MessageHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Message> {
+
+   private StringBuilder currentText = new StringBuilder();
+   private Message.Builder builder = Message.builder();
+   private String name;
+
+   @Override
+   public Message getResult() {
+      try {
+         return builder.build();
+      } catch (NullPointerException e) {
+         return null;
+      } finally {
+         builder = Message.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) {
+      if (qName.equals("MessageId")) {
+         builder.id(currentOrNull(currentText));
+      } else if (qName.equals("ReceiptHandle")) {
+         builder.receiptHandle(currentOrNull(currentText));
+      } else if (qName.equals("MD5OfBody")) {
+         builder.md5(HashCodes.fromBytes(CryptoStreams.hex(currentOrNull(currentText))));
+      } else if (qName.equals("Body")) {
+         builder.body(currentOrNull(currentText));
+      } else if (qName.equals("Name")) {
+         this.name = currentOrNull(currentText);
+      } else if (qName.equals("Value")) {
+         builder.addAttribute(this.name, currentOrNull(currentText));
+         this.name = null;
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/ReceiveMessageResponseHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/ReceiveMessageResponseHandler.java
new file mode 100644
index 0000000..e30c82b
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/ReceiveMessageResponseHandler.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.sqs.domain.Message;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.inject.Inject;
+
+/**
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryReceiveMessage.html"
+ *      >docs</a>
+ * 
+ * @author Adrian Cole
+ */
+public class ReceiveMessageResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<FluentIterable<Message>> {
+
+   private final MessageHandler messageHandler;
+
+   private Builder<Message> messages = ImmutableList.<Message> builder();
+
+   private boolean inMessages;
+
+   @Inject
+   public ReceiveMessageResponseHandler(MessageHandler messageHandler) {
+      this.messageHandler = messageHandler;
+   }
+
+   @Override
+   public FluentIterable<Message> getResult() {
+      return FluentIterable.from(messages.build());
+   }
+
+   @Override
+   public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+      if (equalsOrSuffix(qName, "ReceiveMessageResult")) {
+         inMessages = true;
+      }
+      if (inMessages) {
+         messageHandler.startElement(url, name, qName, attributes);
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) {
+      if (equalsOrSuffix(qName, "ReceiveMessageResult")) {
+         inMessages = false;
+      } else if (equalsOrSuffix(qName, "Message")) {
+         messages.add(messageHandler.getResult());
+      } else if (inMessages) {
+         messageHandler.endElement(uri, name, qName);
+      }
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      if (inMessages) {
+         messageHandler.characters(ch, start, length);
+      }
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexListQueuesResponseHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexListQueuesResponseHandler.java
new file mode 100644
index 0000000..dfcccc0
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexListQueuesResponseHandler.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import java.net.URI;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ReturnStringIf2xx;
+import org.jclouds.sqs.xml.internal.BaseRegexQueueHandler;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+
+/**
+ * 
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
+ *      />
+ * @author Adrian Cole
+ */
+@Singleton
+public class RegexListQueuesResponseHandler extends BaseRegexQueueHandler implements Function<HttpResponse, FluentIterable<URI>> {
+   private final ReturnStringIf2xx returnStringIf200;
+
+   @Inject
+   RegexListQueuesResponseHandler(ReturnStringIf2xx returnStringIf200) {
+      this.returnStringIf200 = returnStringIf200;
+   }
+
+   @Override
+   public FluentIterable<URI> apply(HttpResponse response) {
+      return parse(returnStringIf200.apply(response));
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexMessageIdAndMD5Handler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexMessageIdAndMD5Handler.java
new file mode 100644
index 0000000..c7cf3c0
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexMessageIdAndMD5Handler.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.inject.Inject;
+
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ReturnStringIf2xx;
+import org.jclouds.sqs.domain.MessageIdAndMD5;
+
+import com.google.common.base.Function;
+import com.google.common.hash.HashCodes;
+import com.google.inject.Singleton;
+
+/**
+ * 
+ * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QuerySendMessage.html"
+ *      />
+ * @author Adrian Cole
+ */
+@Singleton
+public class RegexMessageIdAndMD5Handler implements Function<HttpResponse, MessageIdAndMD5> {
+   private static final Pattern pattern = Pattern.compile("<MessageId>([\\S&&[^<]]+)</MessageId>\\s*<MD5OfMessageBody>([\\S&&[^<]]+)</MD5OfMessageBody>", Pattern.DOTALL);
+   private final ReturnStringIf2xx returnStringIf200;
+
+   @Inject
+   public RegexMessageIdAndMD5Handler(ReturnStringIf2xx returnStringIf200) {
+      this.returnStringIf200 = returnStringIf200;
+   }
+
+   @Override
+   public MessageIdAndMD5 apply(HttpResponse response) {
+      String content = returnStringIf200.apply(response);
+      if (content != null) {
+         Matcher matcher = pattern.matcher(content);
+         if (matcher.find()) {
+            return MessageIdAndMD5.builder()
+                                  .id(matcher.group(1))
+                                  .md5(HashCodes.fromBytes(CryptoStreams.hex(matcher.group(2))))
+                                  .build();
+         }
+      }
+      return null;
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexQueueHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexQueueHandler.java
new file mode 100644
index 0000000..1308545
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexQueueHandler.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import java.net.URI;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ReturnStringIf2xx;
+import org.jclouds.sqs.xml.internal.BaseRegexQueueHandler;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+
+/**
+ * 
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
+ *      />
+ * @author Adrian Cole
+ */
+@Singleton
+public class RegexQueueHandler extends BaseRegexQueueHandler implements Function<HttpResponse, URI> {
+   private final ReturnStringIf2xx returnStringIf200;
+
+   @Inject
+   public RegexQueueHandler(ReturnStringIf2xx returnStringIf200) {
+      this.returnStringIf200 = returnStringIf200;
+   }
+
+   @Override
+   public URI apply(HttpResponse response) {
+      return Iterables.getOnlyElement(parse(returnStringIf200.apply(response)));
+   }
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/SendMessageBatchResponseHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/SendMessageBatchResponseHandler.java
new file mode 100644
index 0000000..bb7780e
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/SendMessageBatchResponseHandler.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import javax.inject.Inject;
+
+import org.jclouds.sqs.domain.MessageIdAndMD5;
+
+/**
+ * @see <a
+ *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QuerySendMessageBatch.html"
+ *      >docs</a>
+ * 
+ * @author Adrian Cole
+ */
+public class SendMessageBatchResponseHandler extends BatchResponseHandler<MessageIdAndMD5> {
+
+   @Inject
+   protected SendMessageBatchResponseHandler(SendMessageBatchResultEntryHandler resultHandler,
+         BatchErrorHandler errorHandler) {
+      super("SendMessageBatchResultEntry", resultHandler, errorHandler);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/SendMessageBatchResultEntryHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/SendMessageBatchResultEntryHandler.java
new file mode 100644
index 0000000..0474e2e
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/SendMessageBatchResultEntryHandler.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.sqs.domain.MessageIdAndMD5;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.hash.HashCodes;
+
+/**
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryReceiveMessage.html"
+ *      />
+ * 
+ * @author Adrian Cole
+ */
+public class SendMessageBatchResultEntryHandler extends
+      ParseSax.HandlerForGeneratedRequestWithResult<Map.Entry<String, MessageIdAndMD5>> {
+
+   private StringBuilder currentText = new StringBuilder();
+   private MessageIdAndMD5.Builder builder = MessageIdAndMD5.builder();
+   private String id;
+
+   @Override
+   public Entry<String, MessageIdAndMD5> getResult() {
+      try {
+         return Iterables.getOnlyElement(ImmutableMap.of(id, builder.build()).entrySet());
+      } finally {
+         builder = MessageIdAndMD5.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) {
+      if (qName.equals("Id")) {
+         this.id = currentOrNull(currentText);
+      } else if (qName.equals("MessageId")) {
+         builder.id(currentOrNull(currentText));
+      } else if (qName.equals("MD5OfMessageBody")) {
+         builder.md5(HashCodes.fromBytes(CryptoStreams.hex(currentOrNull(currentText))));
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/TextFromSingleElementHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/TextFromSingleElementHandler.java
new file mode 100644
index 0000000..cfde3d1
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/TextFromSingleElementHandler.java
@@ -0,0 +1,63 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.util.SaxUtils.currentOrNull;
+
+import org.jclouds.http.functions.ParseSax;
+
+import com.google.common.base.Function;
+
+/**
+ * looks for a single value in the xml
+ * 
+ * @author Adrian Cole
+ */
+public abstract class TextFromSingleElementHandler<V> extends ParseSax.HandlerForGeneratedRequestWithResult<V>
+      implements Function<String, V> {
+   private final String elementName;
+
+   protected TextFromSingleElementHandler(String elementName) {
+      this.elementName = checkNotNull(elementName, "elementName");
+   }
+
+   private StringBuilder currentText = new StringBuilder();
+   private String text;
+
+   @Override
+   public V getResult() {
+      return apply(text);
+   }
+
+   // this could be done with regex, if we had an unescaper
+   @Override
+   public void endElement(String uri, String name, String qName) {
+      if (qName.equals(elementName)) {
+         text = currentOrNull(currentText);
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/ValueHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/ValueHandler.java
new file mode 100644
index 0000000..c3764d3
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/ValueHandler.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml;
+
+import javax.inject.Inject;
+
+/**
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryGetQueueAttributes.html"
+ *      />
+ * 
+ * @author Adrian Cole
+ */
+public class ValueHandler extends TextFromSingleElementHandler<String> {
+   @Inject
+   protected ValueHandler(String elementName) {
+      super("Value");
+   }
+
+   @Override
+   public String apply(String in) {
+      return in;
+   }
+
+}
diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java
new file mode 100644
index 0000000..e191f44
--- /dev/null
+++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.xml.internal;
+
+import java.net.URI;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.inject.Singleton;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+/**
+ * 
+ * @see <a href=
+ *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
+ *      />
+ * @author Adrian Cole
+ */
+@Singleton
+public class BaseRegexQueueHandler {
+   protected final Pattern pattern = Pattern.compile("<QueueUrl>(https://[\\S&&[^<]]+)</QueueUrl>");
+
+   public FluentIterable<URI> parse(String in) {
+      Builder<URI> queues = ImmutableSet.<URI> builder();
+      Matcher matcher = pattern.matcher(in);
+      while (matcher.find()) {
+         String uriText = matcher.group(1);
+         if (!Strings.isNullOrEmpty(uriText))
+            queues.add(URI.create(uriText));
+      }
+      return FluentIterable.from(queues.build());
+   }
+
+}
diff --git a/apis/sqs/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/apis/sqs/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000..8831fe1
--- /dev/null
+++ b/apis/sqs/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
@@ -0,0 +1 @@
+org.jclouds.sqs.SQSApiMetadata
\ No newline at end of file
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/SQSApiMetadataTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/SQSApiMetadataTest.java
new file mode 100644
index 0000000..4f5eeda
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/SQSApiMetadataTest.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs;
+
+import org.jclouds.View;
+import org.jclouds.rest.internal.BaseRestApiMetadataTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "SQSApiMetadataTest")
+public class SQSApiMetadataTest extends BaseRestApiMetadataTest {
+
+   // no queue abstraction, yet
+   public SQSApiMetadataTest() {
+      super(new SQSApiMetadata(), ImmutableSet.<TypeToken<? extends View>> of());
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/BulkMessageApiLiveTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/BulkMessageApiLiveTest.java
new file mode 100644
index 0000000..9e0fe24
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/BulkMessageApiLiveTest.java
@@ -0,0 +1,130 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static org.jclouds.sqs.options.ReceiveMessageOptions.Builder.attribute;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import java.net.URI;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.jclouds.sqs.domain.BatchResult;
+import org.jclouds.sqs.domain.Message;
+import org.jclouds.sqs.domain.MessageIdAndMD5;
+import org.jclouds.sqs.internal.BaseSQSApiLiveTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.internal.annotations.Sets;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.Iterables;
+import com.google.common.hash.Hashing;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", singleThreaded = true, testName = "BulkMessageApiLiveTest")
+public class BulkMessageApiLiveTest extends BaseSQSApiLiveTest {
+
+   private ImmutableMap<String, String> idPayload;
+
+   public BulkMessageApiLiveTest() {
+      prefix = prefix + "-bulk";
+
+      Builder<String, String> builder = ImmutableMap.<String, String> builder();
+      for (int i = 0; i < 10; i++) {
+         String message = "hardyharhar" + i;
+         builder.put(i + "", message);
+      }
+      idPayload = builder.build();
+   }
+
+   @BeforeClass(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      super.setupContext();
+      recreateQueueInRegion(prefix, null);
+   }
+
+   public void testSendMessages() {
+      for (URI queue : queues) {
+         BatchResult<? extends MessageIdAndMD5> acks = api().getMessageApiForQueue(queue).send(idPayload);
+
+         assertEquals(acks.size(), idPayload.size(), "error sending " + acks);
+         assertEquals(acks.keySet(), idPayload.keySet());
+
+         for (Entry<String, ? extends MessageIdAndMD5> entry : acks.entrySet()) {
+            assertEquals(entry.getValue().getMD5(),
+                  Hashing.md5().hashString(idPayload.get(entry.getKey()), Charsets.UTF_8), "bad md5 for: " + entry);
+         }
+      }
+   }
+
+   private Iterable<String> receiptHandles;
+
+   @Test(dependsOnMethods = "testSendMessages")
+   public void testChangeMessageVisibility() {
+      for (URI queue : queues) {
+         MessageApi api = api().getMessageApiForQueue(queue);
+         
+         Set<Message> messages = collectMessages(api);
+
+         receiptHandles = Iterables.transform(messages, new Function<Message, String>() {
+            @Override
+            public String apply(Message in) {
+               return in.getReceiptHandle();
+            }
+         });
+
+         // hidden message, so we can't see it
+         assertNull(api.receive());
+
+         // this should unhide it
+         BatchResult<String> acks = api.changeVisibility(receiptHandles, 0);
+         assertEquals(acks.size(), messages.size(), "error changing visibility " + acks);
+
+         // so we can see it again
+         assertEquals(collectMessages(api).size(), messages.size());
+      }
+   }
+
+   protected Set<Message> collectMessages(MessageApi api) {
+      // you are not guaranteed to get all messages in the same request
+      Set<Message> messages = Sets.newLinkedHashSet();
+      while (messages.size() != idPayload.size())
+         messages.addAll(api.receive(idPayload.size(), attribute("None").visibilityTimeout(5)).toImmutableSet());
+      return messages;
+   }
+
+   @Test(dependsOnMethods = "testChangeMessageVisibility")
+   public void testDeleteMessage() throws InterruptedException {
+      for (URI queue : queues) {
+         BatchResult<String> acks = api().getMessageApiForQueue(queue).delete(receiptHandles);
+         assertEquals(acks.size(), Iterables.size(receiptHandles), "error deleting messages " + acks);
+         assertNoMessages(queue);
+      }
+   }
+
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/MessageApiExpectTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/MessageApiExpectTest.java
new file mode 100644
index 0000000..da2fa1b
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/MessageApiExpectTest.java
@@ -0,0 +1,542 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.sqs.SQSApi;
+import org.jclouds.sqs.internal.BaseSQSApiExpectTest;
+import org.jclouds.sqs.parse.ChangeMessageVisibilityBatchResponseTest;
+import org.jclouds.sqs.parse.DeleteMessageBatchResponseTest;
+import org.jclouds.sqs.parse.ReceiveMessageResponseTest;
+import org.jclouds.sqs.parse.SendMessageBatchResponseTest;
+import org.jclouds.sqs.parse.SendMessageResponseTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Iterables;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "MessageApiExpectTest")
+public class MessageApiExpectTest extends BaseSQSApiExpectTest {
+   
+   public HttpRequest sendMessage = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "SendMessage")
+         .addFormParam("MessageBody", "hardyharhar")
+         .addFormParam("Signature", "PVzszzgIcT1xt9%2BEzGzWB2Bt8zDadBc48HsgF89AoJE%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testSendMessageWhenResponseIs2xx() throws Exception {
+      
+      HttpResponse sendMessageResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType("/send_message.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(sendMessage, sendMessageResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).send("hardyharhar").toString(),
+            new SendMessageResponseTest().expected().toString());
+   }
+   
+   public HttpRequest sendMessageIterable = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "SendMessageBatch")
+         .addFormParam("SendMessageBatchRequestEntry.1.Id", "1")
+         .addFormParam("SendMessageBatchRequestEntry.1.MessageBody", "payload1")
+         .addFormParam("SendMessageBatchRequestEntry.2.Id", "2")
+         .addFormParam("SendMessageBatchRequestEntry.2.MessageBody", "payload2")
+         .addFormParam("Signature", "2AYMDMLhoLncALJgBfHBGfOkaTB5ut3PeFRJeWffxdI%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testSendMessageIterableWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/send_message_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(sendMessageIterable, sendMessageResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).send(ImmutableSet.of("payload1", "payload2"))
+            .toString(), new SendMessageBatchResponseTest().expected().toString());
+   }
+
+   public HttpRequest sendMessageMap = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "SendMessageBatch")
+         .addFormParam("SendMessageBatchRequestEntry.1.Id", "foo1")
+         .addFormParam("SendMessageBatchRequestEntry.1.MessageBody", "payload1")
+         .addFormParam("SendMessageBatchRequestEntry.2.Id", "foo2")
+         .addFormParam("SendMessageBatchRequestEntry.2.MessageBody", "payload2")
+         .addFormParam("Signature", "f9v8e%2FrPXTI3zhBYMhg7U8yCfvPqHjAV8bFjhGL6%2BXc%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+   
+   public void testSendMessageMapWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/send_message_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(sendMessageMap, sendMessageResponse);
+
+      assertEquals(
+            apiWhenExist.getMessageApiForQueue(queue)
+                  .send(ImmutableMap.of("foo1", "payload1", "foo2", "payload2")).toString(),
+            new SendMessageBatchResponseTest().expected().toString());
+   }
+   
+   public HttpRequest sendMessageWithDelayMap = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "SendMessageBatch")
+         .addFormParam("SendMessageBatchRequestEntry.1.DelaySeconds", "10")
+         .addFormParam("SendMessageBatchRequestEntry.1.Id", "foo1")
+         .addFormParam("SendMessageBatchRequestEntry.1.MessageBody", "payload1")
+         .addFormParam("SendMessageBatchRequestEntry.2.DelaySeconds", "10")
+         .addFormParam("SendMessageBatchRequestEntry.2.Id", "foo2")
+         .addFormParam("SendMessageBatchRequestEntry.2.MessageBody", "payload2")
+         .addFormParam("Signature", "COjjEaJ76EwziEFtkT2FuSRSbrCIu%2FhlJf1Zmu7cYoU%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testSendMessageWithDelayMapWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/send_message_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(sendMessageWithDelayMap, sendMessageResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).sendWithDelay(ImmutableMap.<String, String>builder()
+            .put("foo1", "payload1")
+            .put("foo2", "payload2")
+            .build(), 10)
+            .toString(), new SendMessageBatchResponseTest().expected().toString());
+   }
+
+   public HttpRequest sendMessageWithDelayIterable = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "SendMessageBatch")
+         .addFormParam("SendMessageBatchRequestEntry.1.DelaySeconds", "10")
+         .addFormParam("SendMessageBatchRequestEntry.1.Id", "1")
+         .addFormParam("SendMessageBatchRequestEntry.1.MessageBody", "payload1")
+         .addFormParam("SendMessageBatchRequestEntry.2.DelaySeconds", "10")
+         .addFormParam("SendMessageBatchRequestEntry.2.Id", "2")
+         .addFormParam("SendMessageBatchRequestEntry.2.MessageBody", "payload2")
+         .addFormParam("Signature", "8AVNvSVXPSnoXjJAc6h1rysMBBZPnSycbnmD2%2FqpdV8%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+   
+   public void testSendMessageWithDelayIterableWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/send_message_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(sendMessageWithDelayIterable, sendMessageResponse);
+
+      assertEquals(
+            apiWhenExist.getMessageApiForQueue(queue).sendWithDelay(ImmutableSet.of("payload1", "payload2"), 10)
+                  .toString(), new SendMessageBatchResponseTest().expected().toString());
+   }
+   public HttpRequest sendMessageWithDelaysTable = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "SendMessageBatch")
+         .addFormParam("SendMessageBatchRequestEntry.1.DelaySeconds", "1")
+         .addFormParam("SendMessageBatchRequestEntry.1.Id", "foo1")
+         .addFormParam("SendMessageBatchRequestEntry.1.MessageBody", "payload1")
+         .addFormParam("SendMessageBatchRequestEntry.2.DelaySeconds", "10")
+         .addFormParam("SendMessageBatchRequestEntry.2.Id", "foo2")
+         .addFormParam("SendMessageBatchRequestEntry.2.MessageBody", "payload2")
+         .addFormParam("Signature", "M2X8Al%2BbyyDM%2B9kdN28rMn1yJWl78hJ5i4GnaMZ1sYg%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testSendMessageWithDelaysTableWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/send_message_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(sendMessageWithDelaysTable, sendMessageResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).sendWithDelays(ImmutableTable.<String, String, Integer>builder()
+            .put("foo1", "payload1", 1)
+            .put("foo2", "payload2", 10)
+            .build())
+            .toString(), new SendMessageBatchResponseTest().expected().toString());
+   }
+
+   public HttpRequest sendMessageWithDelaysMap = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "SendMessageBatch")
+         .addFormParam("SendMessageBatchRequestEntry.1.DelaySeconds", "1")
+         .addFormParam("SendMessageBatchRequestEntry.1.Id", "1")
+         .addFormParam("SendMessageBatchRequestEntry.1.MessageBody", "payload1")
+         .addFormParam("SendMessageBatchRequestEntry.2.DelaySeconds", "10")
+         .addFormParam("SendMessageBatchRequestEntry.2.Id", "2")
+         .addFormParam("SendMessageBatchRequestEntry.2.MessageBody", "payload2")
+         .addFormParam("Signature", "nbA4UnKDAuQCiCcvQHH%2F1UjMMeo2s3d94A27Q3t9SlI%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+   
+   public void testSendMessageWithDelaysMapWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/send_message_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(sendMessageWithDelaysMap, sendMessageResponse);
+
+      assertEquals(
+            apiWhenExist.getMessageApiForQueue(queue).sendWithDelays(ImmutableMap.of("payload1", 1, "payload2", 10))
+                  .toString(), new SendMessageBatchResponseTest().expected().toString());
+   }
+   
+   public HttpRequest receiveMessage = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "ReceiveMessage")
+         .addFormParam("Signature", "UURXsAjggoaz5P1h2EFswRd8Ji9euHmXhHvrAmIqM1E%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testReceiveMessageWhenResponseIs2xx() throws Exception {
+      
+      HttpResponse receiveMessageResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType("/messages.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(receiveMessage, receiveMessageResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).receive().toString(),
+            Iterables.get(new ReceiveMessageResponseTest().expected(), 0).toString());
+   }
+   
+
+   public HttpRequest receiveMessages = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "ReceiveMessage")
+         .addFormParam("MaxNumberOfMessages", "10")
+         .addFormParam("Signature", "pZ9B4%2BTBvQA4n0joP4t8ue5x0xmKMd9prpVLVoT%2F7qU%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testReceiveMessagesWhenResponseIs2xx() throws Exception {
+      
+      HttpResponse receiveMessagesResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType("/messages.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(receiveMessages, receiveMessagesResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).receive(10).toString(), new ReceiveMessageResponseTest()
+            .expected().toString());
+   }
+   
+   public HttpRequest deleteMessage = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "DeleteMessage")
+         .addFormParam("ReceiptHandle", "eXJYhj5rDr9cAe")
+         .addFormParam("Signature", "9%2FkuCc2i78gMsmul%2BRsOPcdQ1OLUKrItqgGIRRBJb8M%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testDeleteMessageWhenResponseIs2xx() throws Exception {
+
+      HttpResponse deleteMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromStringWithContentType(
+                        "<DeleteMessageResponse><ResponseMetadata><RequestId>b5293cb5-d306-4a17-9048-b263635abe42</RequestId></ResponseMetadata></DeleteMessageResponse>",
+                        "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(deleteMessage, deleteMessageResponse);
+
+      apiWhenExist.getMessageApiForQueue(queue).delete("eXJYhj5rDr9cAe");
+   }
+
+   public HttpRequest deleteMessageIterable = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "DeleteMessageBatch")
+         .addFormParam("DeleteMessageBatchRequestEntry.1.Id", "1")
+         .addFormParam("DeleteMessageBatchRequestEntry.1.ReceiptHandle", "eXJYhj5rDr9cAe")
+         .addFormParam("DeleteMessageBatchRequestEntry.2.Id", "2")
+         .addFormParam("DeleteMessageBatchRequestEntry.2.ReceiptHandle", "fffeeerrr")
+         .addFormParam("Signature", "S4xIobjm3LOkJvibeI2X54nxKJw9r1a5zj%2FdvHlfDMY%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testDeleteMessageIterableWhenResponseIs2xx() throws Exception {
+
+      HttpResponse deleteMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/delete_message_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(deleteMessageIterable, deleteMessageResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).delete(ImmutableSet.of("eXJYhj5rDr9cAe", "fffeeerrr"))
+            .toString(), new DeleteMessageBatchResponseTest().expected().toString());
+   }
+
+   public HttpRequest deleteMessageMap = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "DeleteMessageBatch")
+         .addFormParam("DeleteMessageBatchRequestEntry.1.Id", "foo1")
+         .addFormParam("DeleteMessageBatchRequestEntry.1.ReceiptHandle", "eXJYhj5rDr9cAe")
+         .addFormParam("DeleteMessageBatchRequestEntry.2.Id", "foo2")
+         .addFormParam("DeleteMessageBatchRequestEntry.2.ReceiptHandle", "fffeeerrr")
+         .addFormParam("Signature", "kwHC3F3ZoJvfibhZWVTeIwFHUzoaVMR4OViyJbsmuV0%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testDeleteMessageMapWhenResponseIs2xx() throws Exception {
+
+      HttpResponse deleteMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/delete_message_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(deleteMessageMap, deleteMessageResponse);
+
+      assertEquals(
+            apiWhenExist.getMessageApiForQueue(queue)
+                  .delete(ImmutableMap.of("foo1", "eXJYhj5rDr9cAe", "foo2", "fffeeerrr")).toString(),
+            new DeleteMessageBatchResponseTest().expected().toString());
+   }
+   
+   public HttpRequest changeMessageVisibility = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "ChangeMessageVisibility")
+         .addFormParam("ReceiptHandle", "eXJYhj5rDr9cAe")
+         .addFormParam("Signature", "gvmSHleGLkmszYU6aURCBImuec2k0O3pg3tAYhDvkNs%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("VisibilityTimeout", "10")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testChangeMessageVisibilityWhenResponseIs2xx() throws Exception {
+
+      HttpResponse changeMessageVisibilityResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromStringWithContentType(
+                        "<ChangeMessageVisibilityResponse><ResponseMetadata><RequestId>b5293cb5-d306-4a17-9048-b263635abe42</RequestId></ResponseMetadata></ChangeMessageVisibilityResponse>",
+                        "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(changeMessageVisibility, changeMessageVisibilityResponse);
+
+      apiWhenExist.getMessageApiForQueue(queue).changeVisibility("eXJYhj5rDr9cAe", 10);
+   }
+
+   public HttpRequest changeMessageVisibilityTable = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "ChangeMessageVisibilityBatch")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.Id", "foo1")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.ReceiptHandle", "aaaaaaaaa")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.VisibilityTimeout", "1")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.Id", "foo2")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.ReceiptHandle", "bbbbbbbbb")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.VisibilityTimeout", "10")
+         .addFormParam("Signature", "KjDusYiiC3hTdy3ZxLwBRHryrNoNaFb2AHJqUDu3mtQ%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testChangeMessageVisibilityTableWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/change_message_visibility_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(changeMessageVisibilityTable, sendMessageResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).changeVisibility(ImmutableTable.<String, String, Integer>builder()
+            .put("foo1", "aaaaaaaaa", 1)
+            .put("foo2", "bbbbbbbbb", 10)
+            .build())
+            .toString(), new ChangeMessageVisibilityBatchResponseTest().expected().toString());
+   }
+
+   public HttpRequest changeMessageVisibilityMap = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "ChangeMessageVisibilityBatch")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.Id", "1")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.ReceiptHandle", "aaaaaaaaa")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.VisibilityTimeout", "1")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.Id", "2")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.ReceiptHandle", "bbbbbbbbb")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.VisibilityTimeout", "10")
+         .addFormParam("Signature", "zj2cftkpHtiYb9iOjPR3AhcVhoobi0JvOy22PvQJtho%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+   
+   public void testChangeMessageVisibilityMapWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/change_message_visibility_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(changeMessageVisibilityMap, sendMessageResponse);
+
+      assertEquals(
+            apiWhenExist.getMessageApiForQueue(queue).changeVisibility(ImmutableMap.of("aaaaaaaaa", 1, "bbbbbbbbb", 10))
+                  .toString(), new ChangeMessageVisibilityBatchResponseTest().expected().toString());
+   }
+
+   public HttpRequest changeMessageVisibilityMapInt = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "ChangeMessageVisibilityBatch")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.Id", "foo1")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.ReceiptHandle", "aaaaaaaaa")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.VisibilityTimeout", "10")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.Id", "foo2")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.ReceiptHandle", "bbbbbbbbb")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.VisibilityTimeout", "10")
+         .addFormParam("Signature", "y%2FgaaxoE5wrG2P7NIAyfDo7DTgRx2PLJUi9%2FzNnWQ6A%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testChangeMessageVisibilityMapIntWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/change_message_visibility_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(changeMessageVisibilityMapInt, sendMessageResponse);
+
+      assertEquals(apiWhenExist.getMessageApiForQueue(queue).changeVisibility(ImmutableMap.<String, String>builder()
+            .put("foo1", "aaaaaaaaa")
+            .put("foo2", "bbbbbbbbb")
+            .build(), 10)
+            .toString(), new ChangeMessageVisibilityBatchResponseTest().expected().toString());
+   }
+
+   public HttpRequest changeMessageVisibilityIterableInt = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "ChangeMessageVisibilityBatch")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.Id", "1")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.ReceiptHandle", "aaaaaaaaa")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.1.VisibilityTimeout", "10")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.Id", "2")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.ReceiptHandle", "bbbbbbbbb")
+         .addFormParam("ChangeMessageVisibilityBatchRequestEntry.2.VisibilityTimeout", "10")
+         .addFormParam("Signature", "f5aq7zdKFErM3%2BIdtDX5NOzPO7mqCRzPGj2wUUEWjgE%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+   
+   public void testChangeMessageVisibilityIterableIntWhenResponseIs2xx() throws Exception {
+
+      HttpResponse sendMessageResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResourceWithContentType("/change_message_visibility_batch.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(changeMessageVisibilityIterableInt, sendMessageResponse);
+
+      assertEquals(
+            apiWhenExist.getMessageApiForQueue(queue).changeVisibility(ImmutableSet.of("aaaaaaaaa", "bbbbbbbbb"), 10)
+                  .toString(), new ChangeMessageVisibilityBatchResponseTest().expected().toString());
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/MessageApiLiveTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/MessageApiLiveTest.java
new file mode 100644
index 0000000..0e2a3ea
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/MessageApiLiveTest.java
@@ -0,0 +1,94 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static org.jclouds.sqs.options.ReceiveMessageOptions.Builder.attribute;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import java.net.URI;
+
+import org.jclouds.sqs.internal.BaseSQSApiLiveTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Charsets;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.Hashing;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", singleThreaded = true, testName = "MessageApiLiveTest")
+public class MessageApiLiveTest extends BaseSQSApiLiveTest {
+
+   public MessageApiLiveTest() {
+      prefix = prefix + "-message";
+   }
+
+   @BeforeClass(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      super.setupContext();
+      recreateQueueInRegion(prefix, null);
+   }
+
+   String message = "hardyharhar";
+   HashCode md5 = Hashing.md5().hashString(message, Charsets.UTF_8);
+
+   public void testSendMessage() {
+      for (URI queue : queues) {
+         assertEquals(api().getMessageApiForQueue(queue).send(message).getMD5(), md5);
+      }
+   }
+
+   @Test(dependsOnMethods = "testSendMessage")
+   public void testReceiveMessageWithoutHidingMessage() {
+      for (URI queue : queues) {
+         assertEquals(api().getMessageApiForQueue(queue).receive(attribute("All").visibilityTimeout(0)).getMD5(), md5);
+      }
+   }
+
+   String receiptHandle;
+
+   @Test(dependsOnMethods = "testReceiveMessageWithoutHidingMessage")
+   public void testChangeMessageVisibility() {
+      for (URI queue : queues) {
+         MessageApi api = api().getMessageApiForQueue(queue);
+         // start hiding it at 5 seconds
+         receiptHandle = api.receive(attribute("None").visibilityTimeout(5)).getReceiptHandle();
+         // hidden message, so we can't see it
+         assertNull(api.receive());
+         // this should unhide it
+         api.changeVisibility(receiptHandle, 0);
+         // so we can see it again
+         assertEquals(api.receive(attribute("All").visibilityTimeout(0)).getMD5(), md5);
+      }
+   }
+
+   @Test(dependsOnMethods = "testChangeMessageVisibility")
+   public void testDeleteMessage() throws InterruptedException {
+      for (URI queue : queues) {
+         api().getMessageApiForQueue(queue).delete(receiptHandle);
+         assertNoMessages(queue);
+      }
+   }
+
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiExpectTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiExpectTest.java
new file mode 100644
index 0000000..037de11
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiExpectTest.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.sqs.SQSApi;
+import org.jclouds.sqs.domain.Action;
+import org.jclouds.sqs.internal.BaseSQSApiExpectTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "PermissionApiExpectTest")
+public class PermissionApiExpectTest extends BaseSQSApiExpectTest {
+   
+   public HttpRequest addPermission = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "AddPermission")
+         .addFormParam("ActionName.1", "ReceiveMessage")
+         .addFormParam("AWSAccountId.1", "125074342641")
+         .addFormParam("Label", "testLabel")
+         .addFormParam("Signature", "J9sV4q1rJ7dWYJDQp9JxsfEKNXQhpQBYIwBYi1IeXV0%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testAddPermissionWhenResponseIs2xx() throws Exception {
+
+      HttpResponse addPermissionResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromStringWithContentType(
+                        "<AddPermissionsResponse><ResponseMetadata><RequestId>b5293cb5-d306-4a17-9048-b263635abe42</RequestId></ResponseMetadata></AddPermissionsResponse>",
+                        "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(addPermission, addPermissionResponse);
+
+      apiWhenExist.getPermissionApiForQueue(queue).addPermissionToAccount("testLabel", Action.RECEIVE_MESSAGE, "125074342641");
+   }
+   
+   public HttpRequest removePermission = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "RemovePermission")
+         .addFormParam("Label", "testLabel")
+         .addFormParam("Signature", "VOA0L1uRVKQDQL1Klt0cYUajGoxN4Ur%2B7ISQ2I4RpRs%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testRemovePermissionWhenResponseIs2xx() throws Exception {
+
+      HttpResponse removePermissionResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromStringWithContentType(
+                        "<RemovePermissionsResponse><ResponseMetadata><RequestId>b5293cb5-d306-4a17-9048-b263635abe42</RequestId></ResponseMetadata></RemovePermissionsResponse>",
+                        "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(removePermission, removePermissionResponse);
+
+      apiWhenExist.getPermissionApiForQueue(queue).remove("testLabel");
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiLiveTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiLiveTest.java
new file mode 100644
index 0000000..b1aa629
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiLiveTest.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static com.google.common.collect.Iterables.get;
+import static org.jclouds.concurrent.MoreExecutors.sameThreadExecutor;
+import static org.jclouds.providers.AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint;
+import static org.jclouds.sqs.reference.SQSParameters.ACTION;
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+import org.jclouds.ContextBuilder;
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.concurrent.config.ExecutorServiceModule;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.XMLResponseParser;
+import org.jclouds.sqs.domain.Action;
+import org.jclouds.sqs.domain.QueueAttributes;
+import org.jclouds.sqs.internal.BaseSQSApiLiveTest;
+import org.jclouds.sqs.xml.ValueHandler;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.inject.Module;
+
+/**
+ * 
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", singleThreaded = true, testName = "PermissionApiLiveTest")
+public class PermissionApiLiveTest extends BaseSQSApiLiveTest {
+
+   public PermissionApiLiveTest() {
+      prefix = prefix + "-permission";
+   }
+
+   @BeforeClass(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      super.setupContext();
+      recreateQueueInRegion(prefix, null);
+   }
+
+   @Timeout(duration = 5, timeUnit = TimeUnit.SECONDS)
+   static interface AnonymousAttributesApi {
+      String getQueueArn();
+   }
+
+   static interface AnonymousAttributesAsyncApi {
+      @POST
+      @Path("/")
+      @FormParams(keys = { ACTION, "AttributeName.1" }, values = { "GetQueueAttributes", "QueueArn" })
+      @XMLResponseParser(ValueHandler.class)
+      ListenableFuture<String> getQueueArn();
+   }
+
+   public void testAddAnonymousPermission() throws InterruptedException {
+      for (URI queue : queues) {
+         QueueAttributes attributes = api().getQueueApi().getAttributes(queue);
+         assertNoPermissions(queue);
+
+         String accountToAuthorize = getAccountToAuthorize(queue);
+         api().getPermissionApiForQueue(queue).addPermissionToAccount("fubar", Action.GET_QUEUE_ATTRIBUTES,
+               accountToAuthorize);
+
+         String policyForAuthorizationByAccount = assertPolicyPresent(queue);
+
+         String policyForAnonymous = policyForAuthorizationByAccount.replace("\"" + accountToAuthorize + "\"", "\"*\"");
+         api().getQueueApi().setAttribute(queue, "Policy", policyForAnonymous);
+
+         assertEquals(getAnonymousAttributesApi(queue).getQueueArn(), attributes.getQueueArn());
+      }
+   }
+
+   protected String getAccountToAuthorize(URI queue) {
+      return get(Splitter.on('/').split(queue.getPath()), 1);
+   }
+
+   @Test(dependsOnMethods = "testAddAnonymousPermission")
+   public void testRemovePermission() throws InterruptedException {
+      for (URI queue : queues) {
+         api().getPermissionApiForQueue(queue).remove("fubar");
+         assertNoPermissions(queue);
+      }
+   }
+
+   private AnonymousAttributesApi getAnonymousAttributesApi(URI queue) {
+      return ContextBuilder
+            .newBuilder(
+                  forClientMappedToAsyncClientOnEndpoint(AnonymousAttributesApi.class,
+                        AnonymousAttributesAsyncApi.class, queue.toASCIIString()))
+            .modules(ImmutableSet.<Module> of(new ExecutorServiceModule(sameThreadExecutor(), sameThreadExecutor())))
+            .buildInjector().getInstance(AnonymousAttributesApi.class);
+   }
+
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiExpectTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiExpectTest.java
new file mode 100644
index 0000000..a9b09a1
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiExpectTest.java
@@ -0,0 +1,169 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.sqs.SQSApi;
+import org.jclouds.sqs.functions.MapToQueueAttributesTest;
+import org.jclouds.sqs.internal.BaseSQSApiExpectTest;
+import org.jclouds.sqs.parse.CreateQueueResponseTest;
+import org.jclouds.sqs.parse.GetQueueAttributesResponseTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "QueueApiExpectTest")
+public class QueueApiExpectTest extends BaseSQSApiExpectTest {
+   
+   public HttpRequest createQueue = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "CreateQueue")
+         .addFormParam("QueueName", "queueName")
+         .addFormParam("Signature", "I7tmwiCzJ9cvw79pmlz1rOILh2C2ZV6OpLk23JGx6AU%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testCreateQueueWhenResponseIs2xx() throws Exception {
+      
+      HttpResponse createQueueResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType("/create_queue.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(createQueue, createQueueResponse);
+
+      assertEquals(apiWhenExist.getQueueApi().create("queueName").toString(), new CreateQueueResponseTest().expected()
+            .toString());
+   }
+   
+   public HttpRequest getQueueAttribute = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "GetQueueAttributes")
+         .addFormParam("AttributeName.1", "VisibilityTimeout")
+         .addFormParam("Signature", "AfydayBBaIk4UGikHHY1CFNmOOAcTnogpFWydZyNass%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testGetQueueAttributeWhenResponseIs2xx() throws Exception {
+      
+      HttpResponse getQueueAttributeResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromStringWithContentType(
+                        "<GetQueueAttributesResponse><GetQueueAttributesResult><Attribute><Name>VisibilityTimeout</Name><Value>30</Value></Attribute></GetQueueAttributesResult></GetQueueAttributesResponse>",
+                        "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(getQueueAttribute, getQueueAttributeResponse);
+
+      assertEquals(apiWhenExist.getQueueApi().getAttribute(queue, "VisibilityTimeout"), "30");
+   }
+   
+   public HttpRequest getQueueAttributes = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "GetQueueAttributes")
+         .addFormParam("AttributeName.1", "All")
+         .addFormParam("Signature", "welFLn0TV6JlH6s6s60XZTJeJfFXGiXN4qNPrBx7aHc%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testGetQueueAttributesWhenResponseIs2xx() throws Exception {
+      
+      HttpResponse getQueueAttributesResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType("/attributes.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(getQueueAttributes, getQueueAttributesResponse);
+
+      assertEquals(apiWhenExist.getQueueApi().getAttributes(queue).toString(), new MapToQueueAttributesTest()
+            .expected().toString());
+   }
+   
+   public HttpRequest getQueueAttributesSubset = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "GetQueueAttributes")
+         .addFormParam("AttributeName.1", "VisibilityTimeout")
+         .addFormParam("AttributeName.2", "DelaySeconds")
+         .addFormParam("Signature", "9KaiOOWWyFPTVMOnyHA3ZoXbPBPSD4AZ4q460UNMfDs%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testGetQueueAttributesSubsetWhenResponseIs2xx() throws Exception {
+      
+      HttpResponse getQueueAttributesSubsetResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResourceWithContentType("/attributes.xml", "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(getQueueAttributesSubset, getQueueAttributesSubsetResponse);
+
+      assertEquals(apiWhenExist.getQueueApi()
+            .getAttributes(queue, ImmutableSet.of("VisibilityTimeout", "DelaySeconds")).toString(),
+            new GetQueueAttributesResponseTest().expected().toString());
+   }
+   
+   public HttpRequest setQueueAttribute = HttpRequest.builder()
+         .method("POST")
+         .endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
+         .addHeader("Host", "sqs.us-east-1.amazonaws.com")
+         .addFormParam("Action", "SetQueueAttributes")
+         .addFormParam("Attribute.Name", "MaximumMessageSize")
+         .addFormParam("Attribute.Value", "1")
+         .addFormParam("Signature", "ktBkQ3c%2FrwGcBSec0fkckfo73xmcoTuub5fxudM1qh0%3D")
+         .addFormParam("SignatureMethod", "HmacSHA256")
+         .addFormParam("SignatureVersion", "2")
+         .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z")
+         .addFormParam("Version", "2011-10-01")
+         .addFormParam("AWSAccessKeyId", "identity").build();
+
+   public void testSetQueueAttributeWhenResponseIs2xx() throws Exception {
+
+      HttpResponse setQueueAttributeResponse = HttpResponse.builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromStringWithContentType(
+                        "<SetQueueAttributesResponse><ResponseMetadata><RequestId>b5293cb5-d306-4a17-9048-b263635abe42</RequestId></ResponseMetadata></SetQueueAttributesResponse>",
+                        "text/xml")).build();
+
+      SQSApi apiWhenExist = requestSendsResponse(setQueueAttribute, setQueueAttributeResponse);
+
+      apiWhenExist.getQueueApi().setAttribute(queue, "MaximumMessageSize", "1");
+   }
+
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiLiveTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiLiveTest.java
new file mode 100644
index 0000000..799ff2d
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiLiveTest.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.features;
+
+import static com.google.common.collect.Iterables.getLast;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.jclouds.sqs.internal.BaseSQSApiLiveTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", singleThreaded = true, testName = "QueueApiLiveTest")
+public class QueueApiLiveTest extends BaseSQSApiLiveTest {
+
+   public QueueApiLiveTest() {
+      prefix = prefix + "-queue";
+   }
+
+   @Test
+   public void testListQueues() throws InterruptedException {
+      listQueuesInRegion(null);
+   }
+
+   protected void listQueuesInRegion(String region) throws InterruptedException {
+      FluentIterable<URI> allResults = api().getQueueApiForRegion(region).list();
+      assertNotNull(allResults);
+      if (allResults.size() >= 1) {
+         URI queue = getLast(allResults);
+         assertQueueInList(region, queue);
+      }
+   }
+
+   @Test
+   public void testCanRecreateQueueGracefully() throws InterruptedException {
+      recreateQueueInRegion(prefix, null);
+      recreateQueueInRegion(prefix, null);
+   }
+
+   @Test(dependsOnMethods = "testCanRecreateQueueGracefully")
+   public void testGetQueueAttributes() {
+      for (URI queue : queues) {
+         Map<String, String> attributes = api().getQueueApi().getAttributes(queue, ImmutableSet.of("All"));
+         assertEquals(api().getQueueApi().getAttributes(queue, attributes.keySet()), attributes);
+      }
+   }
+
+   @Test(dependsOnMethods = "testGetQueueAttributes")
+   public void testSetQueueAttribute() {
+      for (URI queue : queues) {
+         api().getQueueApi().setAttribute(queue, "MaximumMessageSize", "1024");
+         assertEquals(api().getQueueApi().getAttributes(queue).getMaximumMessageSize(), 1024);
+      }
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/functions/MapToQueueAttributesTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/functions/MapToQueueAttributesTest.java
new file mode 100644
index 0000000..203a5b7
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/functions/MapToQueueAttributesTest.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Date;
+
+import org.jclouds.sqs.domain.QueueAttributes;
+import org.jclouds.sqs.parse.GetQueueAttributesResponseTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "MapToQueueAttributesTest")
+public class MapToQueueAttributesTest {
+
+   public void test() {
+      
+
+      QueueAttributes expected = expected();
+      
+      MapToQueueAttributes fn = new MapToQueueAttributes();
+
+      QueueAttributes result = fn.apply(new GetQueueAttributesResponseTest().expected());
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public QueueAttributes expected() {
+      return QueueAttributes.builder()
+                            .queueArn("arn:aws:sqs:us-east-1:993194456877:adrian-sqs1")
+                            .approximateNumberOfMessages(0)
+                            .approximateNumberOfMessagesNotVisible(0)
+                            .approximateNumberOfMessagesDelayed(0)
+                            .createdTimestamp(new Date(1347566436l))
+                            .lastModifiedTimestamp(new Date(1347566436))
+                            .visibilityTimeout(30)
+                            .maximumMessageSize(65536)
+                            .messageRetentionPeriod(345600)
+                            .delaySeconds(0)
+                            .build();
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/handlers/SQSErrorRetryHandlerTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/handlers/SQSErrorRetryHandlerTest.java
new file mode 100644
index 0000000..d9de520
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/handlers/SQSErrorRetryHandlerTest.java
@@ -0,0 +1,138 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.handlers;
+
+import static org.easymock.EasyMock.createMock;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.aws.domain.AWSError;
+import org.jclouds.aws.util.AWSUtils;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Tests behavior of {@code SQSErrorRetryHandler}
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "SQSErrorRetryHandlerTest")
+public class SQSErrorRetryHandlerTest {
+
+   String code = "AWS.SimpleQueueService.QueueDeletedRecently";
+   AWSError error;
+   HttpResponse response = HttpResponse.builder().statusCode(400)
+         .payload(String.format("<Error><Code>%s</Code></Error>", code)).build();
+
+   public SQSErrorRetryHandlerTest() {
+      error = new AWSError();
+      error.setCode(code);
+   }
+   
+   public void testQueueDeletedRecentlyRetriesWhen59SleepsAndTries() {
+
+      SQSErrorRetryHandler retry = new SQSErrorRetryHandler(createMock(AWSUtils.class),
+            createMock(BackoffLimitedRetryHandler.class), ImmutableSet.<String> of(), 60, 100);
+
+      HttpCommand command = createHttpCommandForFailureCount(59);
+
+      Stopwatch watch = new Stopwatch().start();
+      assertTrue(retry.shouldRetryRequestOnError(command, response, error));
+      assertEquals(command.getFailureCount(), 60);
+      // allow for slightly inaccurate system timers
+      assertTrue(watch.stop().elapsedTime(TimeUnit.MILLISECONDS) >= 98);
+   }
+   
+
+   
+   public void testQueueDeletedRecentlyRetriesWhen60DoesntTry() {
+
+      SQSErrorRetryHandler retry = new SQSErrorRetryHandler(createMock(AWSUtils.class),
+            createMock(BackoffLimitedRetryHandler.class), ImmutableSet.<String> of(), 60, 100);
+
+      HttpCommand command = createHttpCommandForFailureCount(60);
+
+      Stopwatch watch = new Stopwatch().start();
+      assertFalse(retry.shouldRetryRequestOnError(command, response, error));
+      assertEquals(command.getFailureCount(), 61);
+      assertTrue(watch.stop().elapsedTime(TimeUnit.MILLISECONDS) < 100);
+   }
+   
+   //TODO: make a builder for this
+   HttpCommand createHttpCommandForFailureCount(final int failureCount) {
+      return new HttpCommand() {
+         int fCount = failureCount;
+
+         @Override
+         public int incrementRedirectCount() {
+            return 0;
+         }
+
+         @Override
+         public int getRedirectCount() {
+            return 0;
+         }
+
+         @Override
+         public boolean isReplayable() {
+            return false;
+         }
+
+         @Override
+         public int incrementFailureCount() {
+            return ++fCount;
+         }
+
+         @Override
+         public int getFailureCount() {
+            return fCount;
+         }
+
+         @Override
+         public HttpRequest getCurrentRequest() {
+            return null;
+         }
+
+         @Override
+         public void setCurrentRequest(HttpRequest request) {
+
+         }
+
+         @Override
+         public void setException(Exception exception) {
+         }
+
+         @Override
+         public Exception getException() {
+            return null;
+         }
+      };
+   }
+
+
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiExpectTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiExpectTest.java
new file mode 100644
index 0000000..dc92282
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiExpectTest.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.internal;
+
+import org.jclouds.sqs.SQSApi;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+public class BaseSQSApiExpectTest extends BaseSQSExpectTest<SQSApi> {
+
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiLiveTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiLiveTest.java
new file mode 100644
index 0000000..96031c8
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiLiveTest.java
@@ -0,0 +1,161 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.internal;
+
+import static com.google.common.collect.Iterables.getLast;
+import static org.jclouds.sqs.options.ListQueuesOptions.Builder.queuePrefix;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.jclouds.apis.BaseContextLiveTest;
+import org.jclouds.rest.RestContext;
+import org.jclouds.sqs.SQSApi;
+import org.jclouds.sqs.SQSApiMetadata;
+import org.jclouds.sqs.SQSAsyncApi;
+import org.jclouds.sqs.domain.Message;
+import org.jclouds.sqs.features.QueueApi;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+import com.google.common.util.concurrent.Uninterruptibles;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live")
+public class BaseSQSApiLiveTest extends BaseContextLiveTest<RestContext<SQSApi, SQSAsyncApi>> {
+
+   protected String prefix = System.getProperty("user.name") + "-sqs";
+
+   public BaseSQSApiLiveTest() {
+      provider = "sqs";
+   }
+
+   protected Set<URI> queues = Sets.newHashSet();
+
+   protected String recreateQueueInRegion(String queueName, String region) {
+      QueueApi api = api().getQueueApiForRegion(region);
+      FluentIterable<URI> result = api.list(queuePrefix(queueName));
+      if (result.size() >= 1) {
+         api.delete(getLast(result));
+      }
+      URI queue = api.create(queueName);
+      assertQueueInList(region, queue);
+      queues.add(queue);
+      return queueName;
+   }
+
+   @Override
+   protected TypeToken<RestContext<SQSApi, SQSAsyncApi>> contextType() {
+      return SQSApiMetadata.CONTEXT_TOKEN;
+   }
+
+   protected String assertPolicyPresent(final URI queue) {
+      final AtomicReference<String> policy = new AtomicReference<String>();
+      assertEventually(new Runnable() {
+         public void run() {
+            String policyForAuthorizationByAccount = api().getQueueApi().getAttribute(queue, "Policy");
+
+            assertNotNull(policyForAuthorizationByAccount);
+            policy.set(policyForAuthorizationByAccount);
+         }
+      });
+      return policy.get();
+   }
+
+   protected void assertNoPermissions(final URI queue) {
+      assertEventually(new Runnable() {
+         public void run() {
+            String policy = api().getQueueApi().getAttribute(queue, "Policy");
+            assertTrue(policy == null || policy.indexOf("\"Statement\":[]") != -1, policy);
+         }
+      });
+   }
+
+   protected void assertNoMessages(final URI queue) {
+      assertEventually(new Runnable() {
+         public void run() {
+            Message message = api().getMessageApiForQueue(queue).receive();
+            assertNull(message, "message: " + message + " left in queue " + queue);
+         }
+      });
+   }
+
+   protected void assertQueueInList(final String region, URI queue) {
+      final URI finalQ = queue;
+      assertEventually(new Runnable() {
+         public void run() {
+            FluentIterable<URI> result = api().getQueueApiForRegion(region).list();
+            assertNotNull(result);
+            assert result.size() >= 1 : result;
+            assertTrue(result.contains(finalQ), finalQ + " not in " + result);
+         }
+      });
+   }
+
+   private static final int INCONSISTENCY_WINDOW = 10000;
+
+   /**
+    * Due to eventual consistency, container commands may not return correctly
+    * immediately. Hence, we will try up to the inconsistency window to see if
+    * the assertion completes.
+    */
+   protected static void assertEventually(Runnable assertion) {
+      long start = System.currentTimeMillis();
+      AssertionError error = null;
+      for (int i = 0; i < 30; i++) {
+         try {
+            assertion.run();
+            if (i > 0)
+               System.err.printf("%d attempts and %dms asserting %s%n", i + 1, System.currentTimeMillis() - start,
+                     assertion.getClass().getSimpleName());
+            return;
+         } catch (AssertionError e) {
+            error = e;
+         }
+         Uninterruptibles.sleepUninterruptibly(INCONSISTENCY_WINDOW / 30, TimeUnit.MILLISECONDS);
+      }
+      if (error != null)
+         throw error;
+   }
+
+   @Override
+   @AfterClass(groups = "live")
+   protected void tearDownContext() {
+      for (URI queue : queues) {
+         api().getQueueApi().delete(queue);
+      }
+      super.tearDownContext();
+   }
+
+   protected SQSApi api() {
+      return context.getApi();
+   }
+
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSExpectTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSExpectTest.java
new file mode 100644
index 0000000..082cb1d
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSExpectTest.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.internal;
+
+import java.net.URI;
+
+import org.jclouds.date.DateService;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.internal.BaseRestApiExpectTest;
+import org.jclouds.sqs.config.SQSRestClientModule;
+
+import com.google.inject.Module;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+public class BaseSQSExpectTest<T> extends BaseRestApiExpectTest<T> {
+   protected URI queue = URI.create("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/");
+
+   public BaseSQSExpectTest() {
+      provider = "sqs";
+   }
+
+   @ConfiguresRestClient
+   private static final class TestSQSRestClientModule extends SQSRestClientModule {
+
+      @Override
+      protected String provideTimeStamp(final DateService dateService) {
+         return "2009-11-08T15:54:08.897Z";
+      }
+   }
+
+   @Override
+   protected Module createModule() {
+      return new TestSQSRestClientModule();
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/options/CreateQueueOptionsTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/options/CreateQueueOptionsTest.java
new file mode 100644
index 0000000..ffae910
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/options/CreateQueueOptionsTest.java
@@ -0,0 +1,43 @@
+package org.jclouds.sqs.options;
+
+import static org.jclouds.sqs.options.CreateQueueOptions.Builder.attribute;
+import static org.jclouds.sqs.options.CreateQueueOptions.Builder.visibilityTimeout;
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Tests behavior of {@code CreateQueueOptions}
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "CreateQueueOptionsTest")
+public class CreateQueueOptionsTest {
+
+   public void testVisibilityTimeout() {
+      CreateQueueOptions options = new CreateQueueOptions().visibilityTimeout(2);
+      assertEquals(ImmutableSet.of("VisibilityTimeout"), options.buildFormParameters().get("Attribute.1.Name"));
+      assertEquals(ImmutableSet.of("2"), options.buildFormParameters().get("Attribute.1.Value"));
+   }
+
+   public void testVisibilityTimeoutStatic() {
+      CreateQueueOptions options = visibilityTimeout(2);
+      assertEquals(ImmutableSet.of("VisibilityTimeout"), options.buildFormParameters().get("Attribute.1.Name"));
+      assertEquals(ImmutableSet.of("2"), options.buildFormParameters().get("Attribute.1.Value"));
+   }
+
+   public void testAttribute() {
+      CreateQueueOptions options = new CreateQueueOptions().attribute("DelaySeconds", "1");
+      assertEquals(ImmutableSet.of("DelaySeconds"), options.buildFormParameters().get("Attribute.1.Name"));
+      assertEquals(ImmutableSet.of("1"), options.buildFormParameters().get("Attribute.1.Value"));
+   }
+
+   public void testAttributeStatic() {
+      CreateQueueOptions options = attribute("DelaySeconds", "1");
+      assertEquals(ImmutableSet.of("DelaySeconds"), options.buildFormParameters().get("Attribute.1.Name"));
+      assertEquals(ImmutableSet.of("1"), options.buildFormParameters().get("Attribute.1.Value"));
+   }
+
+}
diff --git a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/options/ListQueuesOptionsTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/options/ListQueuesOptionsTest.java
similarity index 100%
rename from sandbox-apis/sqs/src/test/java/org/jclouds/sqs/options/ListQueuesOptionsTest.java
rename to apis/sqs/src/test/java/org/jclouds/sqs/options/ListQueuesOptionsTest.java
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/options/ReceiveMessageOptionsTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/options/ReceiveMessageOptionsTest.java
new file mode 100644
index 0000000..815a8a4
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/options/ReceiveMessageOptionsTest.java
@@ -0,0 +1,39 @@
+package org.jclouds.sqs.options;
+
+import static org.jclouds.sqs.options.ReceiveMessageOptions.Builder.attribute;
+import static org.jclouds.sqs.options.ReceiveMessageOptions.Builder.visibilityTimeout;
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Tests behavior of {@code ReceiveMessageOptions}
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "ReceiveMessageOptionsTest")
+public class ReceiveMessageOptionsTest {
+
+   public void testVisibilityTimeout() {
+      ReceiveMessageOptions options = new ReceiveMessageOptions().visibilityTimeout(2);
+      assertEquals(ImmutableSet.of("2"), options.buildFormParameters().get("VisibilityTimeout"));
+   }
+
+   public void testVisibilityTimeoutStatic() {
+      ReceiveMessageOptions options = visibilityTimeout(2);
+      assertEquals(ImmutableSet.of("2"), options.buildFormParameters().get("VisibilityTimeout"));
+   }
+
+   public void testAttribute() {
+      ReceiveMessageOptions options = new ReceiveMessageOptions().attribute("All");
+      assertEquals(ImmutableSet.of("All"), options.buildFormParameters().get("AttributeName.1"));
+   }
+
+   public void testAttributeStatic() {
+      ReceiveMessageOptions options = attribute("All");
+      assertEquals(ImmutableSet.of("All"), options.buildFormParameters().get("AttributeName.1"));
+   }
+
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/options/SendMessageOptionsTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/options/SendMessageOptionsTest.java
new file mode 100644
index 0000000..5bbebdb
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/options/SendMessageOptionsTest.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.options;
+
+import static org.jclouds.sqs.options.SendMessageOptions.Builder.delaySeconds;
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Tests possible uses of SendMessageOptions and SendMessageOptions.Builder.*
+ * 
+ * @author Adrian Cole
+ */
+public class SendMessageOptionsTest {
+
+   @Test
+   public void testDelaySeconds() {
+      SendMessageOptions options = new SendMessageOptions();
+      options.delaySeconds(3);
+      assertEquals(options.buildFormParameters().get("DelaySeconds"), ImmutableSet.of("3"));
+   }
+
+   @Test
+   public void testDelaySecondsStatic() {
+      SendMessageOptions options = delaySeconds(3);
+      assertEquals(options.buildFormParameters().get("DelaySeconds"), ImmutableSet.of("3"));
+   }
+
+   public void testNoDelaySeconds() {
+      delaySeconds(null);
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/parse/ChangeMessageVisibilityBatchResponseTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/parse/ChangeMessageVisibilityBatchResponseTest.java
new file mode 100644
index 0000000..4e40613
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/parse/ChangeMessageVisibilityBatchResponseTest.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.jclouds.sqs.domain.BatchResult;
+import org.jclouds.sqs.xml.ChangeMessageVisibilityBatchResponseHandler;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "ChangeMessageVisibilityBatchResponseTest")
+public class ChangeMessageVisibilityBatchResponseTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/change_message_visibility_batch.xml");
+
+      BatchResult<String> expected = expected();
+
+      ChangeMessageVisibilityBatchResponseHandler handler = injector.getInstance(ChangeMessageVisibilityBatchResponseHandler.class);
+      BatchResult<String> result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public BatchResult<String> expected() {
+      return BatchResult.<String> builder()
+            .put("change_visibility_msg_2","change_visibility_msg_2")
+            .put("change_visibility_msg_3","change_visibility_msg_3")
+            .build();
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/parse/CreateQueueResponseTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/parse/CreateQueueResponseTest.java
new file mode 100644
index 0000000..f3d9226
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/parse/CreateQueueResponseTest.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.net.URI;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ReturnStringIf2xx;
+import org.jclouds.sqs.xml.RegexQueueHandler;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "CreateQueueResponseTest")
+public class CreateQueueResponseTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/create_queue.xml");
+
+      URI expected = expected();
+
+      RegexQueueHandler handler = new RegexQueueHandler(new ReturnStringIf2xx());
+      URI result = handler.apply(HttpResponse.builder().statusCode(200).payload(is).build());
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public URI expected() {
+      return URI.create("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11");
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/parse/DeleteMessageBatchResponseTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/parse/DeleteMessageBatchResponseTest.java
new file mode 100644
index 0000000..c7e4ce4
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/parse/DeleteMessageBatchResponseTest.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.jclouds.sqs.domain.BatchResult;
+import org.jclouds.sqs.xml.DeleteMessageBatchResponseHandler;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "DeleteMessageBatchResponseTest")
+public class DeleteMessageBatchResponseTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/delete_message_batch.xml");
+
+      BatchResult<String> expected = expected();
+
+      DeleteMessageBatchResponseHandler handler = injector.getInstance(DeleteMessageBatchResponseHandler.class);
+      BatchResult<String> result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public BatchResult<String> expected() {
+      return BatchResult.<String> builder()
+            .put("msg1","msg1")
+            .put("msg2","msg2")
+            .build();
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/parse/GetQueueAttributesResponseTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/parse/GetQueueAttributesResponseTest.java
new file mode 100644
index 0000000..143d293
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/parse/GetQueueAttributesResponseTest.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.util.Map;
+
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.jclouds.sqs.xml.AttributesHandler;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "GetQueueAttributesResponseTest")
+public class GetQueueAttributesResponseTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/attributes.xml");
+
+      Map<String, String> expected = expected();
+
+      AttributesHandler handler = injector.getInstance(AttributesHandler.class);
+      Map<String, String> result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public Map<String, String> expected() {
+      return ImmutableMap.<String, String>builder()
+            .put("QueueArn", "arn:aws:sqs:us-east-1:993194456877:adrian-sqs1")
+            .put("ApproximateNumberOfMessages", "0")
+            .put("ApproximateNumberOfMessagesNotVisible", "0")
+            .put("ApproximateNumberOfMessagesDelayed", "0")
+            .put("CreatedTimestamp", "1347566436")
+            .put("LastModifiedTimestamp", "1347566436")
+            .put("VisibilityTimeout","30")
+            .put("MaximumMessageSize", "65536")
+            .put("MessageRetentionPeriod", "345600")
+            .put("DelaySeconds", "0")
+            .build();
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/parse/ReceiveMessageResponseTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/parse/ReceiveMessageResponseTest.java
new file mode 100644
index 0000000..0afa837
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/parse/ReceiveMessageResponseTest.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.jclouds.sqs.domain.Message;
+import org.jclouds.sqs.xml.ReceiveMessageResponseHandler;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.hash.HashCodes;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "ReceiveMessageResponseTest")
+public class ReceiveMessageResponseTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/messages.xml");
+
+      FluentIterable<Message> expected = expected();
+
+      ReceiveMessageResponseHandler handler = injector.getInstance(ReceiveMessageResponseHandler.class);
+      FluentIterable<Message> result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public FluentIterable<Message> expected() {
+      return FluentIterable.from(ImmutableList.of(Message
+            .builder()
+            .id("5fea7756-0ea4-451a-a703-a558b933e274")
+            .receiptHandle(
+                  "+eXJYhj5rDr9cAe/9BuheT5fysi9BoqtEZSkO7IazVbNHg60eCCINxLqaSVv2pFHrWeWNpZwbleSkWRbCtZaQGgpOx/3cWJZiNSG1KKlJX4IOwISFvb3FwByMx4w0lnINeXzcw2VcKQXNrCatO9gdIiVPvJC3SCKatYM/7YTidtjqc8igrtYW2E2mHlCy3NXPCeXxP4tSvyEwIxpDAmMT7IF0mWvTHS6+JBUtFUsrmi61oIHlESNrD1OjdB1QQw+kdvJ6VbsntbJNNYKw+YqdqWNpZkiGQ8y1z9OdHsr1+4=")
+            .md5(HashCodes.fromBytes(CryptoStreams.hex("fafb00f5732ab283681e124bf8747ed1")))
+            .body("This is a test message")
+            .addAttribute("SenderId", "195004372649")
+            .addAttribute("SentTimestamp", "1238099229000")
+            .addAttribute("ApproximateReceiveCount", "5")
+            .addAttribute("ApproximateFirstReceiveTimestamp", "1250700979248").build()));
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/parse/SendMessageBatchResponseTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/parse/SendMessageBatchResponseTest.java
new file mode 100644
index 0000000..fcafc10
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/parse/SendMessageBatchResponseTest.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.http.functions.BaseHandlerTest;
+import org.jclouds.sqs.domain.BatchResult;
+import org.jclouds.sqs.domain.MessageIdAndMD5;
+import org.jclouds.sqs.xml.SendMessageBatchResponseHandler;
+import org.testng.annotations.Test;
+
+import com.google.common.hash.HashCodes;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "SendMessageBatchResponseTest")
+public class SendMessageBatchResponseTest extends BaseHandlerTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/send_message_batch.xml");
+
+      BatchResult<MessageIdAndMD5> expected = expected();
+
+      SendMessageBatchResponseHandler handler = injector.getInstance(SendMessageBatchResponseHandler.class);
+      BatchResult<MessageIdAndMD5> result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public BatchResult<MessageIdAndMD5> expected() {
+      return BatchResult
+            .<MessageIdAndMD5> builder()
+            .put("test_msg_001",
+                  MessageIdAndMD5.builder().id("0a5231c7-8bff-4955-be2e-8dc7c50a25fa")
+                        .md5(HashCodes.fromBytes(CryptoStreams.hex("0e024d309850c78cba5eabbeff7cae71"))).build())
+            .put("test_msg_002",
+                  MessageIdAndMD5.builder().id("15ee1ed3-87e7-40c1-bdaa-2e49968ea7e9")
+                        .md5(HashCodes.fromBytes(CryptoStreams.hex("7fb8146a82f95e0af155278f406862c2"))).build())
+            .build();
+   }
+}
diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/parse/SendMessageResponseTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/parse/SendMessageResponseTest.java
new file mode 100644
index 0000000..c49c5d2
--- /dev/null
+++ b/apis/sqs/src/test/java/org/jclouds/sqs/parse/SendMessageResponseTest.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.sqs.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ReturnStringIf2xx;
+import org.jclouds.sqs.domain.MessageIdAndMD5;
+import org.jclouds.sqs.xml.RegexMessageIdAndMD5Handler;
+import org.testng.annotations.Test;
+
+import com.google.common.hash.HashCodes;
+
+/**
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "SendMessageResponseTest")
+public class SendMessageResponseTest {
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/send_message.xml");
+
+      MessageIdAndMD5 expected = expected();
+
+      RegexMessageIdAndMD5Handler handler = new RegexMessageIdAndMD5Handler(new ReturnStringIf2xx());
+      MessageIdAndMD5 result = handler.apply(HttpResponse.builder().statusCode(200).payload(is).build());
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public MessageIdAndMD5 expected() {
+      return MessageIdAndMD5.builder().id("c332b2b0-b61f-42d3-8832-d03ebd89f68d")
+            .md5(HashCodes.fromBytes(CryptoStreams.hex("e32aedf2b2b25355d04b1507055532e6"))).build();
+   }
+}
diff --git a/apis/sqs/src/test/resources/attributes.xml b/apis/sqs/src/test/resources/attributes.xml
new file mode 100644
index 0000000..726c246
--- /dev/null
+++ b/apis/sqs/src/test/resources/attributes.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<GetQueueAttributesResponse xmlns="http://queue.amazonaws.com/doc/2011-10-01/">
+	<GetQueueAttributesResult>
+		<Attribute>
+			<Name>QueueArn</Name>
+			<Value>arn:aws:sqs:us-east-1:993194456877:adrian-sqs1</Value>
+		</Attribute>
+		<Attribute>
+			<Name>ApproximateNumberOfMessages</Name>
+			<Value>0</Value>
+		</Attribute>
+		<Attribute>
+			<Name>ApproximateNumberOfMessagesNotVisible</Name>
+			<Value>0</Value>
+		</Attribute>
+		<Attribute>
+			<Name>ApproximateNumberOfMessagesDelayed</Name>
+			<Value>0</Value>
+		</Attribute>
+		<Attribute>
+			<Name>CreatedTimestamp</Name>
+			<Value>1347566436</Value>
+		</Attribute>
+		<Attribute>
+			<Name>LastModifiedTimestamp</Name>
+			<Value>1347566436</Value>
+		</Attribute>
+		<Attribute>
+			<Name>VisibilityTimeout</Name>
+			<Value>30</Value>
+		</Attribute>
+		<Attribute>
+			<Name>MaximumMessageSize</Name>
+			<Value>65536</Value>
+		</Attribute>
+		<Attribute>
+			<Name>MessageRetentionPeriod</Name>
+			<Value>345600</Value>
+		</Attribute>
+		<Attribute>
+			<Name>DelaySeconds</Name>
+			<Value>0</Value>
+		</Attribute>
+	</GetQueueAttributesResult>
+	<ResponseMetadata>
+		<RequestId>35566a87-caa1-5841-b60b-224bf7068bf5</RequestId>
+	</ResponseMetadata>
+</GetQueueAttributesResponse>
\ No newline at end of file
diff --git a/apis/sqs/src/test/resources/change_message_visibility_batch.xml b/apis/sqs/src/test/resources/change_message_visibility_batch.xml
new file mode 100644
index 0000000..bfc4707
--- /dev/null
+++ b/apis/sqs/src/test/resources/change_message_visibility_batch.xml
@@ -0,0 +1,13 @@
+<ChangeMessageVisibilityBatchResponse>
+    <ChangeMessageVisibilityBatchResult>
+        <ChangeMessageVisibilityBatchResultEntry>
+            <Id>change_visibility_msg_2</Id>
+        </ChangeMessageVisibilityBatchResultEntry>
+        <ChangeMessageVisibilityBatchResultEntry>
+            <Id>change_visibility_msg_3</Id>
+        </ChangeMessageVisibilityBatchResultEntry>
+    </ChangeMessageVisibilityBatchResult>
+    <ResponseMetadata>
+        <RequestId>ca9668f7-ab1b-4f7a-8859-f15747ab17a7</RequestId>
+    </ResponseMetadata>
+</ChangeMessageVisibilityBatchResponse>
\ No newline at end of file
diff --git a/apis/sqs/src/test/resources/create_queue.xml b/apis/sqs/src/test/resources/create_queue.xml
new file mode 100644
index 0000000..33f78bf
--- /dev/null
+++ b/apis/sqs/src/test/resources/create_queue.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<CreateQueueResponse xmlns="http://queue.amazonaws.com/doc/2011-10-01/">
+	<CreateQueueResult>
+		<QueueUrl>https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11</QueueUrl>
+	</CreateQueueResult>
+	<ResponseMetadata>
+		<RequestId>86f9002d-531a-5868-a452-48e4293ae0a4</RequestId>
+	</ResponseMetadata>
+</CreateQueueResponse>
\ No newline at end of file
diff --git a/apis/sqs/src/test/resources/delete_message_batch.xml b/apis/sqs/src/test/resources/delete_message_batch.xml
new file mode 100644
index 0000000..aeaefa7
--- /dev/null
+++ b/apis/sqs/src/test/resources/delete_message_batch.xml
@@ -0,0 +1,13 @@
+<DeleteMessageBatchResponse>
+    <DeleteMessageBatchResult>
+        <DeleteMessageBatchResultEntry>
+            <Id>msg1</Id>
+        </DeleteMessageBatchResultEntry>
+        <DeleteMessageBatchResultEntry>
+            <Id>msg2</Id>
+        </DeleteMessageBatchResultEntry>
+    </DeleteMessageBatchResult>
+    <ResponseMetadata>
+        <RequestId>d6f86b7a-74d1-4439-b43f-196a1e29cd85</RequestId>
+    </ResponseMetadata>
+</DeleteMessageBatchResponse>
\ No newline at end of file
diff --git a/apis/sqs/src/test/resources/list_queues.xml b/apis/sqs/src/test/resources/list_queues.xml
new file mode 100644
index 0000000..80ad010
--- /dev/null
+++ b/apis/sqs/src/test/resources/list_queues.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<ListQueuesResponse xmlns="http://queue.amazonaws.com/doc/2011-10-01/"><ListQueuesResult><QueueUrl>https://eu-west-1.queue.amazonaws.com/993194456877/adriancole-sqs1</QueueUrl><QueueUrl>https://eu-west-1.queue.amazonaws.com/993194456877/adriancole-sqs111</QueueUrl></ListQueuesResult><ResponseMetadata><RequestId>313c81c8-e345-4c75-ad57-ce4d9d5ff35a</RequestId></ResponseMetadata></ListQueuesResponse>
\ No newline at end of file
diff --git a/sandbox-apis/sqs/src/test/resources/log4j.xml b/apis/sqs/src/test/resources/log4j.xml
similarity index 100%
rename from sandbox-apis/sqs/src/test/resources/log4j.xml
rename to apis/sqs/src/test/resources/log4j.xml
diff --git a/apis/sqs/src/test/resources/messages.xml b/apis/sqs/src/test/resources/messages.xml
new file mode 100644
index 0000000..fd32241
--- /dev/null
+++ b/apis/sqs/src/test/resources/messages.xml
@@ -0,0 +1,35 @@
+<ReceiveMessageResponse>
+  <ReceiveMessageResult>
+    <Message>
+      <MessageId>
+        5fea7756-0ea4-451a-a703-a558b933e274
+      </MessageId>
+      <ReceiptHandle>+eXJYhj5rDr9cAe/9BuheT5fysi9BoqtEZSkO7IazVbNHg60eCCINxLqaSVv2pFHrWeWNpZwbleSkWRbCtZaQGgpOx/3cWJZiNSG1KKlJX4IOwISFvb3FwByMx4w0lnINeXzcw2VcKQXNrCatO9gdIiVPvJC3SCKatYM/7YTidtjqc8igrtYW2E2mHlCy3NXPCeXxP4tSvyEwIxpDAmMT7IF0mWvTHS6+JBUtFUsrmi61oIHlESNrD1OjdB1QQw+kdvJ6VbsntbJNNYKw+YqdqWNpZkiGQ8y1z9OdHsr1+4=</ReceiptHandle>
+      <MD5OfBody>
+        fafb00f5732ab283681e124bf8747ed1
+      </MD5OfBody>
+      <Body>This is a test message</Body>
+      <Attribute>
+        <Name>SenderId</Name>
+        <Value>195004372649</Value>
+      </Attribute>
+      <Attribute>
+        <Name>SentTimestamp</Name>
+        <Value>1238099229000</Value>
+      </Attribute>
+      <Attribute>
+        <Name>ApproximateReceiveCount</Name>
+        <Value>5</Value>
+      </Attribute>
+      <Attribute>
+        <Name>ApproximateFirstReceiveTimestamp</Name>
+        <Value>1250700979248</Value>
+      </Attribute>
+    </Message>
+  </ReceiveMessageResult>
+  <ResponseMetadata>
+    <RequestId>
+      b6633655-283d-45b4-aee4-4e84e0ae6afa
+    </RequestId>
+  </ResponseMetadata>
+</ReceiveMessageResponse>
\ No newline at end of file
diff --git a/apis/sqs/src/test/resources/send_message.xml b/apis/sqs/src/test/resources/send_message.xml
new file mode 100644
index 0000000..13f9f2f
--- /dev/null
+++ b/apis/sqs/src/test/resources/send_message.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2011-10-01/">
+	<SendMessageResult>
+		<MessageId>c332b2b0-b61f-42d3-8832-d03ebd89f68d</MessageId>
+		<MD5OfMessageBody>e32aedf2b2b25355d04b1507055532e6</MD5OfMessageBody>
+	</SendMessageResult>
+	<ResponseMetadata>
+		<RequestId>c6c18089-18ad-52f8-9d06-c840628cb2ea</RequestId>
+	</ResponseMetadata>
+</SendMessageResponse>
\ No newline at end of file
diff --git a/apis/sqs/src/test/resources/send_message_batch.xml b/apis/sqs/src/test/resources/send_message_batch.xml
new file mode 100644
index 0000000..5761d08
--- /dev/null
+++ b/apis/sqs/src/test/resources/send_message_batch.xml
@@ -0,0 +1,17 @@
+<SendMessageBatchResponse>
+	<SendMessageBatchResult>
+		<SendMessageBatchResultEntry>
+			<Id>test_msg_001</Id>
+			<MessageId>0a5231c7-8bff-4955-be2e-8dc7c50a25fa</MessageId>
+			<MD5OfMessageBody>0e024d309850c78cba5eabbeff7cae71</MD5OfMessageBody>
+		</SendMessageBatchResultEntry>
+		<SendMessageBatchResultEntry>
+			<Id>test_msg_002</Id>
+			<MessageId>15ee1ed3-87e7-40c1-bdaa-2e49968ea7e9</MessageId>
+			<MD5OfMessageBody>7fb8146a82f95e0af155278f406862c2</MD5OfMessageBody>
+		</SendMessageBatchResultEntry>
+	</SendMessageBatchResult>
+	<ResponseMetadata>
+		<RequestId>ca1ad5d0-8271-408b-8d0f-1351bf547e74</RequestId>
+	</ResponseMetadata>
+</SendMessageBatchResponse>
\ No newline at end of file
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/CommonSwiftAsyncClient.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/CommonSwiftAsyncClient.java
index b7a9b9f..b31a92c 100644
--- a/apis/swift/src/main/java/org/jclouds/openstack/swift/CommonSwiftAsyncClient.java
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/CommonSwiftAsyncClient.java
@@ -248,5 +248,4 @@
    @Headers(keys = "X-Object-Manifest", values="{container}/{name}")
    ListenableFuture<String> putObjectManifest(@PathParam("container") String container,
                                               @PathParam("name") String name);
-
 }
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/TemporaryUrlKey.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/TemporaryUrlKey.java
new file mode 100644
index 0000000..7cb011b
--- /dev/null
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/TemporaryUrlKey.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.swift;
+
+import javax.inject.Qualifier;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Represents the key used for signing URLs that have temporary access to objects
+ *
+ * @see <a href="http://docs.openstack.org/developer/swift/misc.html#module-swift.common.middleware.tempurl" />
+ * @author Andrei Savu
+ */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
+@Qualifier
+public @interface TemporaryUrlKey {
+}
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobRequestSigner.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobRequestSigner.java
index 7ba1fc8..b14d0f8 100644
--- a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobRequestSigner.java
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/SwiftBlobRequestSigner.java
@@ -18,31 +18,48 @@
  */
 package org.jclouds.openstack.swift.blobstore;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.collect.Iterables.filter;
 import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest;
 
 import java.lang.reflect.Method;
+import java.security.InvalidKeyException;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
+import com.google.inject.Provider;
 import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
+import org.jclouds.crypto.Crypto;
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.date.TimeStamp;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.options.GetOptions;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
 import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
+import org.jclouds.openstack.swift.TemporaryUrlKey;
 import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
 import org.jclouds.openstack.swift.domain.SwiftObject;
 import org.jclouds.rest.internal.RestAnnotationProcessor;
 
 /**
- * 
  * @author Adrian Cole
  */
 @Singleton
 public class SwiftBlobRequestSigner implements BlobRequestSigner {
+
    private final RestAnnotationProcessor<CommonSwiftAsyncClient> processor;
+   private final Crypto crypto;
+
+   private final Provider<Long> unixEpochTimestampProvider;
+   private final Supplier<String> temporaryUrlKeySupplier;
+
    private final BlobToObject blobToObject;
    private final BlobToHttpGetOptions blob2HttpGetOptions;
 
@@ -52,15 +69,21 @@
 
    @Inject
    public SwiftBlobRequestSigner(RestAnnotationProcessor<CommonSwiftAsyncClient> processor, BlobToObject blobToObject,
-            BlobToHttpGetOptions blob2HttpGetOptions) throws SecurityException, NoSuchMethodException {
+                                 BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto, @TimeStamp Provider<Long> unixEpochTimestampProvider,
+                                 @TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier) throws SecurityException, NoSuchMethodException {
       this.processor = checkNotNull(processor, "processor");
+      this.crypto = checkNotNull(crypto, "crypto");
+
+      this.unixEpochTimestampProvider = checkNotNull(unixEpochTimestampProvider, "unixEpochTimestampProvider");
+      this.temporaryUrlKeySupplier = checkNotNull(temporaryUrlKeySupplier, "temporaryUrlKeyProvider");
+
       this.blobToObject = checkNotNull(blobToObject, "blobToObject");
       this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions");
+
       this.getMethod = CommonSwiftAsyncClient.class.getMethod("getObject", String.class, String.class,
-               GetOptions[].class);
+          GetOptions[].class);
       this.deleteMethod = CommonSwiftAsyncClient.class.getMethod("removeObject", String.class, String.class);
       this.createMethod = CommonSwiftAsyncClient.class.getMethod("putObject", String.class, SwiftObject.class);
-
    }
 
    @Override
@@ -69,17 +92,61 @@
    }
 
    @Override
+   public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
+      HttpRequest request = processor.createRequest(getMethod, container, name);
+      return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
+   }
+
+   @Override
+   public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) {
+      return cleanRequest(processor.createRequest(getMethod, container, name, blob2HttpGetOptions.apply(options)));
+   }
+
+   @Override
    public HttpRequest signPutBlob(String container, Blob blob) {
       return cleanRequest(processor.createRequest(createMethod, container, blobToObject.apply(blob)));
    }
 
    @Override
+   public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
+      HttpRequest request = processor.createRequest(createMethod, container, blobToObject.apply(blob));
+      return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
+   }
+
+   @Override
    public HttpRequest signRemoveBlob(String container, String name) {
       return cleanRequest(processor.createRequest(deleteMethod, container, name));
    }
 
-   @Override
-   public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) {
-      return cleanRequest(processor.createRequest(getMethod, container, name, blob2HttpGetOptions.apply(options)));
+   private HttpRequest signForTemporaryAccess(HttpRequest request, long timeInSeconds) {
+      HttpRequest.Builder builder = request.toBuilder();
+      builder.filters(filter(request.getFilters(), instanceOf(AuthenticateRequest.class)));
+
+      String key = temporaryUrlKeySupplier.get();
+      if (key == null) {
+         throw new UnsupportedOperationException();
+      }
+      long expiresInSeconds = unixEpochTimestampProvider.get() + timeInSeconds;
+
+      builder.addQueryParam("temp_url_sig", createSignature(key, createStringToSign(
+          request.getMethod().toUpperCase(), request, expiresInSeconds)));
+      builder.addQueryParam("temp_url_expires", "" + expiresInSeconds);
+
+      return builder.build();
+   }
+
+   private String createStringToSign(String method, HttpRequest request, long expiresInSeconds) {
+      checkArgument(method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("PUT"));
+      return String.format("%s\n%d\n%s", method.toUpperCase(), expiresInSeconds,
+          request.getEndpoint().getPath());
+   }
+
+   private String createSignature(String key, String stringToSign) {
+      try {
+         return CryptoStreams.hex(crypto.hmacSHA1(key.getBytes()).doFinal(stringToSign.getBytes()));
+
+      } catch (InvalidKeyException e) {
+         throw Throwables.propagate(e);
+      }
    }
 }
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java
index 01d39c7..fc93747 100644
--- a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/config/SwiftBlobStoreContextModule.java
@@ -18,26 +18,44 @@
  */
 package org.jclouds.openstack.swift.blobstore.config;
 
+import com.google.common.base.Supplier;
+import com.google.inject.Provides;
+import com.google.inject.TypeLiteral;
 import org.jclouds.blobstore.AsyncBlobStore;
 import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.attr.ConsistencyModel;
 import org.jclouds.blobstore.config.BlobStoreMapModule;
+import org.jclouds.date.TimeStamp;
+import org.jclouds.openstack.swift.TemporaryUrlKey;
 import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore;
 import org.jclouds.openstack.swift.blobstore.SwiftBlobRequestSigner;
 import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Scopes;
+import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
+import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyAsyncApi;
+import org.jclouds.openstack.swift.suppliers.ReturnOrFetchTemporaryUrlKey;
+
+import java.util.UUID;
+
+import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
 
 /**
  * Configures the {@link CloudFilesBlobStoreContext}; requires {@link SwiftAsyncBlobStore}
  * bound.
- * 
+ *
  * @author Adrian Cole
  */
 public class SwiftBlobStoreContextModule extends AbstractModule {
 
+   @Provides
+   @TimeStamp
+   protected Long unixEpochTimestampProvider() {
+      return System.currentTimeMillis() / 1000; /* convert to seconds */
+   }
+
    @Override
    protected void configure() {
       install(new BlobStoreMapModule());
@@ -45,7 +63,12 @@
       bind(AsyncBlobStore.class).to(SwiftAsyncBlobStore.class).in(Scopes.SINGLETON);
       bind(BlobStore.class).to(SwiftBlobStore.class).in(Scopes.SINGLETON);
       bind(BlobRequestSigner.class).to(SwiftBlobRequestSigner.class);
+      configureTemporaryUrlExtension();
    }
 
-
+   protected void configureTemporaryUrlExtension() {
+      bindClientAndAsyncClient(binder(), TemporaryUrlKeyApi.class, TemporaryUrlKeyAsyncApi.class);
+      bind(new TypeLiteral<Supplier<String>>() {
+      }).annotatedWith(TemporaryUrlKey.class).to(ReturnOrFetchTemporaryUrlKey.class);
+   }
 }
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/domain/internal/ObjectInfoImpl.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/domain/internal/ObjectInfoImpl.java
index 3d88cac..e4022ce 100644
--- a/apis/swift/src/main/java/org/jclouds/openstack/swift/domain/internal/ObjectInfoImpl.java
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/domain/internal/ObjectInfoImpl.java
@@ -33,6 +33,7 @@
 import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
 
 /**
  * Class ObjectInfoImpl
@@ -243,6 +244,6 @@
 
    @Override
    public int compareTo(ObjectInfo other) {
-      return ComparisonChain.start().compare(name, other.getName()).compare(container, other.getContainer()).result();
+      return ComparisonChain.start().compare(name, other.getName()).compare(container, other.getContainer(), Ordering.natural().nullsLast()).result();
    }
 }
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/extensions/TemporaryUrlKeyApi.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/extensions/TemporaryUrlKeyApi.java
new file mode 100644
index 0000000..b8a9f48
--- /dev/null
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/extensions/TemporaryUrlKeyApi.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.swift.extensions;
+
+import org.jclouds.concurrent.Timeout;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Andrei Savu
+ * @see <a href="http://docs.rackspace.com/files/api/v1/cf-devguide/content/Public_Access_to_Account-d1a4440.html" />
+ */
+@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
+public interface TemporaryUrlKeyApi {
+   /**
+    * Retrieve the key used to generate Temporary object access URLs
+    *
+    * @return shared secret key or null
+    * @see <a href="http://docs.rackspace.com/files/api/v1/cf-devguide/content/Set_Account_Metadata-d1a4460.html" />
+    */
+   String getTemporaryUrlKey();
+
+   /**
+    * To create a Temporary URL you must first set a key as account metadata.
+    * <p/>
+    * Once the key is set, you should not change it while you still want others to be
+    * able to access your temporary URL. If you change it, the TempURL becomes invalid
+    * (within 60 seconds, which is the cache time for a key) and others will not be allowed
+    * to access it.
+    *
+    * @param temporaryUrlKey
+    * @see <a href="http://docs.rackspace.com/files/api/v1/cf-devguide/content/Set_Account_Metadata-d1a4460.html" />
+    */
+   void setTemporaryUrlKey(String temporaryUrlKey);
+}
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/extensions/TemporaryUrlKeyAsyncApi.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/extensions/TemporaryUrlKeyAsyncApi.java
new file mode 100644
index 0000000..352c719
--- /dev/null
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/extensions/TemporaryUrlKeyAsyncApi.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.swift.extensions;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.openstack.filters.AuthenticateRequest;
+import org.jclouds.openstack.swift.Storage;
+import org.jclouds.openstack.swift.functions.ParseTemporaryUrlKeyFromHeaders;
+import org.jclouds.openstack.swift.reference.SwiftHeaders;
+import org.jclouds.rest.annotations.Endpoint;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SkipEncoding;
+
+import javax.ws.rs.HEAD;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+/**
+ * @author Andrei Savu
+ * @see TemporaryUrlKeyApi
+ */
+@SkipEncoding('/')
+@RequestFilters(AuthenticateRequest.class)
+@Endpoint(Storage.class)
+public interface TemporaryUrlKeyAsyncApi {
+
+   /**
+    * @see TemporaryUrlKeyApi#getTemporaryUrlKey
+    */
+   @HEAD
+   @Path("/")
+   @ResponseParser(ParseTemporaryUrlKeyFromHeaders.class)
+   ListenableFuture<String> getTemporaryUrlKey();
+
+   /**
+    * @see TemporaryUrlKeyApi#setTemporaryUrlKey
+    */
+   @POST
+   @Path("/")
+   ListenableFuture<Void> setTemporaryUrlKey(@HeaderParam(SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY) String key);
+
+}
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/functions/ParseTemporaryUrlKeyFromHeaders.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/functions/ParseTemporaryUrlKeyFromHeaders.java
new file mode 100644
index 0000000..c126fca
--- /dev/null
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/functions/ParseTemporaryUrlKeyFromHeaders.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.swift.functions;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Multimap;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.swift.reference.SwiftHeaders;
+
+import static com.google.common.collect.Iterables.getOnlyElement;
+import static org.jclouds.openstack.swift.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
+
+/**
+ * @author Andrei Savu
+ */
+public class ParseTemporaryUrlKeyFromHeaders implements Function<HttpResponse, String> {
+
+   @Override
+   public String apply(HttpResponse httpResponse) {
+      Multimap<String, String> headers = httpResponse.getHeaders();
+      if (headers.containsKey(ACCOUNT_TEMPORARY_URL_KEY)) {
+         return getOnlyElement(headers.get(ACCOUNT_TEMPORARY_URL_KEY));
+      } else {
+         return null;
+      }
+   }
+}
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/reference/SwiftHeaders.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/reference/SwiftHeaders.java
index 3e8d37d..73e1042 100644
--- a/apis/swift/src/main/java/org/jclouds/openstack/swift/reference/SwiftHeaders.java
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/reference/SwiftHeaders.java
@@ -24,12 +24,15 @@
  */
 public interface SwiftHeaders {
 
+   public static final String ACCOUNT_TEMPORARY_URL_KEY = "X-Account-Meta-Temp-Url-Key";
    public static final String ACCOUNT_BYTES_USED = "X-Account-Bytes-Used";
    public static final String ACCOUNT_CONTAINER_COUNT = "X-Account-Container-Count";
+
    public static final String CONTAINER_BYTES_USED = "X-Container-Bytes-Used";
    public static final String CONTAINER_OBJECT_COUNT = "X-Container-Object-Count";
    public static final String CONTAINER_METADATA_PREFIX = "X-Container-Meta-";
    public static final String CONTAINER_DELETE_METADATA_PREFIX = "X-Remove-Container-Meta-";
+
    public static final String USER_METADATA_PREFIX = "X-Object-Meta-";
    public static final String OBJECT_COPY_FROM = "X-Copy-From";
    
diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/suppliers/ReturnOrFetchTemporaryUrlKey.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/suppliers/ReturnOrFetchTemporaryUrlKey.java
new file mode 100644
index 0000000..0c0aad2
--- /dev/null
+++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/suppliers/ReturnOrFetchTemporaryUrlKey.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy 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.openstack.swift.suppliers;
+
+import com.google.common.base.Supplier;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
+
+import java.util.UUID;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Singleton
+public class ReturnOrFetchTemporaryUrlKey implements Supplier<String> {
+
+   private TemporaryUrlKeyApi client;
+
+   @Inject
+   public ReturnOrFetchTemporaryUrlKey(TemporaryUrlKeyApi client) {
+      this.client = checkNotNull(client, "client");
+   }
+
+   @Override
+   public String get() {
+      String key = client.getTemporaryUrlKey();
+      if (key == null) {
+         client.setTemporaryUrlKey(UUID.randomUUID().toString());
+         return client.getTemporaryUrlKey();
+      }
+      return key;
+   }
+}
diff --git a/apis/swift/src/test/java/org/jclouds/openstack/swift/CommonSwiftClientLiveTest.java b/apis/swift/src/test/java/org/jclouds/openstack/swift/CommonSwiftClientLiveTest.java
index d1a214e..23fbe2d 100644
--- a/apis/swift/src/test/java/org/jclouds/openstack/swift/CommonSwiftClientLiveTest.java
+++ b/apis/swift/src/test/java/org/jclouds/openstack/swift/CommonSwiftClientLiveTest.java
@@ -339,7 +339,7 @@
        assert contentType.startsWith("text/plain") || "application/x-www-form-urlencoded".equals(contentType): contentType;
    }
 
-   private SwiftObject newSwiftObject(String data, String key) throws IOException {
+   protected SwiftObject newSwiftObject(String data, String key) throws IOException {
       SwiftObject object = getApi().newSwiftObject();
       object.getInfo().setName(key);
       object.setPayload(data);
diff --git a/apis/swift/src/test/java/org/jclouds/openstack/swift/CommonSwiftClientTest.java b/apis/swift/src/test/java/org/jclouds/openstack/swift/CommonSwiftClientTest.java
index d677fcb..667f3d0 100644
--- a/apis/swift/src/test/java/org/jclouds/openstack/swift/CommonSwiftClientTest.java
+++ b/apis/swift/src/test/java/org/jclouds/openstack/swift/CommonSwiftClientTest.java
@@ -21,38 +21,47 @@
 import static org.jclouds.Constants.PROPERTY_API_VERSION;
 import static org.jclouds.Constants.PROPERTY_ENDPOINT;
 import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
+import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
 
 import java.net.URI;
 import java.util.Properties;
 
 import javax.inject.Singleton;
 
+import com.google.common.base.Suppliers;
+import com.google.inject.*;
+import com.google.inject.util.Modules;
 import org.jclouds.apis.ApiMetadata;
+import org.jclouds.date.TimeStamp;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
 import org.jclouds.openstack.internal.TestOpenStackAuthenticationModule;
 import org.jclouds.openstack.reference.AuthHeaders;
 import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
 import org.jclouds.openstack.swift.config.SwiftRestClientModule;
+import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
+import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyAsyncApi;
+import org.jclouds.openstack.swift.suppliers.ReturnOrFetchTemporaryUrlKey;
 import org.jclouds.rest.internal.BaseAsyncClientTest;
 import org.jclouds.rest.internal.RestAnnotationProcessor;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableSet;
-import com.google.inject.Module;
-import com.google.inject.Provides;
-import com.google.inject.TypeLiteral;
 
 /**
  * Tests behavior of {@code BindSwiftObjectMetadataToRequest}
- * 
+ *
  * @author Adrian Cole
  */
 // NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
-@Test(groups = "unit", testName = "SwiftClientTest")
+@Test(groups = "unit", testName = "CommonSwiftClientTest")
 public abstract class CommonSwiftClientTest extends BaseAsyncClientTest<SwiftAsyncClient> {
 
+   public static final long UNIX_EPOCH_TIMESTAMP = 123456789L;
+
+   public static final String TEMPORARY_URL_KEY = "get-or-set-X-Account-Meta-Temp-Url-Key";
+
    @Override
    protected TypeLiteral<RestAnnotationProcessor<SwiftAsyncClient>> createTypeLiteral() {
       return new TypeLiteral<RestAnnotationProcessor<SwiftAsyncClient>>() {
@@ -74,10 +83,25 @@
       }
    }
 
+   public static class StaticTimeAndTemporaryUrlKeyModule extends SwiftBlobStoreContextModule {
+      @Override
+      protected Long unixEpochTimestampProvider() {
+         return UNIX_EPOCH_TIMESTAMP;
+      }
+
+      @Override
+      protected void configureTemporaryUrlExtension() {
+         bindClientAndAsyncClient(binder(), TemporaryUrlKeyApi.class, TemporaryUrlKeyAsyncApi.class);
+         bind(new TypeLiteral<Supplier<String>>() {
+         }).annotatedWith(TemporaryUrlKey.class).toInstance(Suppliers.ofInstance(TEMPORARY_URL_KEY));
+      }
+   }
+
+   @Override
    protected ApiMetadata createApiMetadata() {
       return new SwiftApiMetadata().toBuilder().defaultModules(
-               ImmutableSet.<Class<? extends Module>> of(StorageEndpointModule.class, SwiftRestClientModule.class,
-                        SwiftBlobStoreContextModule.class)).build();
+          ImmutableSet.<Class<? extends Module>>of(StorageEndpointModule.class, SwiftRestClientModule.class,
+              StaticTimeAndTemporaryUrlKeyModule.class)).build();
    }
 
    @Override
diff --git a/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/SwiftBlobRequestSignerTest.java b/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/SwiftBlobRequestSignerTest.java
index 7c3c82c..f16199e 100644
--- a/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/SwiftBlobRequestSignerTest.java
+++ b/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/SwiftBlobRequestSignerTest.java
@@ -19,6 +19,7 @@
 package org.jclouds.openstack.swift.blobstore;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 
 import java.io.IOException;
 import java.util.Date;
@@ -43,8 +44,7 @@
    private BlobRequestSigner signer;
    private Factory blobFactory;
 
-   public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
-            NoSuchMethodException, IOException {
+   public void testSignGetBlob() throws Exception {
       HttpRequest request = signer.signGetBlob("container", "name");
 
       assertRequestLineEquals(request, "GET http://storage/container/name HTTP/1.1");
@@ -54,19 +54,18 @@
       assertEquals(request.getFilters().size(), 0);
    }
 
-   public void testSignRemoveBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
-            NoSuchMethodException, IOException {
-      HttpRequest request = signer.signRemoveBlob("container", "name");
+   public void testSignGetBlobWithTime() {
+      HttpRequest request = signer.signGetBlob("container", "name", 120);
 
-      assertRequestLineEquals(request, "DELETE http://storage/container/name HTTP/1.1");
-      assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
+      assertRequestLineEquals(request, "GET http://storage/container/name?" +
+          "temp_url_sig=4759d99d13c826bba0af2c9f0c526ca53c95abaf&temp_url_expires=123456909 HTTP/1.1");
+      assertFalse(request.getHeaders().containsKey("X-Auth-Token"));
       assertPayloadEquals(request, null, null, false);
 
       assertEquals(request.getFilters().size(), 0);
    }
 
-   public void testSignPutBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
-            NoSuchMethodException, IOException {
+   public void testSignPutBlob() throws Exception {
       Blob blob = blobFactory.create(null);
       blob.getMetadata().setName("name");
       blob.setPayload("");
@@ -84,6 +83,37 @@
       assertEquals(request.getFilters().size(), 0);
    }
 
+   public void testSignPutBlobWithTime() throws Exception {
+      Blob blob = blobFactory.create(null);
+
+      blob.getMetadata().setName("name");
+      blob.setPayload("");
+      blob.getPayload().getContentMetadata().setContentLength(2l);
+      blob.getPayload().getContentMetadata().setContentMD5(new byte[]{0, 2, 4, 8});
+      blob.getPayload().getContentMetadata().setContentType("text/plain");
+      blob.getPayload().getContentMetadata().setExpires(new Date(1000));
+
+      HttpRequest request = signer.signPutBlob("container", blob, 120 /* seconds */);
+
+      assertRequestLineEquals(request, "PUT http://storage/container/name?" +
+          "temp_url_sig=490690286130adac9e7144d85b320a00b1bf9e2b&temp_url_expires=123456909 HTTP/1.1");
+
+      assertFalse(request.getHeaders().containsKey("X-Auth-Token"));
+      assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[]{0, 2, 4, 8}, new Date(1000));
+
+      assertEquals(request.getFilters().size(), 0);
+   }
+
+   public void testSignRemoveBlob() throws Exception {
+      HttpRequest request = signer.signRemoveBlob("container", "name");
+
+      assertRequestLineEquals(request, "DELETE http://storage/container/name HTTP/1.1");
+      assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
+      assertPayloadEquals(request, null, null, false);
+
+      assertEquals(request.getFilters().size(), 0);
+   }
+
    @BeforeClass
    protected void setupFactory() throws IOException {
       super.setupFactory();
diff --git a/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/integration/SwiftBlobLiveTest.java b/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/integration/SwiftBlobLiveTest.java
index 5aa1b49..c1b0ff7 100644
--- a/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/integration/SwiftBlobLiveTest.java
+++ b/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/integration/SwiftBlobLiveTest.java
@@ -19,11 +19,16 @@
 package org.jclouds.openstack.swift.blobstore.integration;
 
 import java.util.Properties;
+import java.util.UUID;
 
 import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
 import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
+import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
 import org.testng.annotations.Test;
 
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
 /**
  * 
  * @author James Murty
diff --git a/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/integration/SwiftBlobSignerLiveTest.java b/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/integration/SwiftBlobSignerLiveTest.java
index 019e66b..9c6ed48 100644
--- a/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/integration/SwiftBlobSignerLiveTest.java
+++ b/apis/swift/src/test/java/org/jclouds/openstack/swift/blobstore/integration/SwiftBlobSignerLiveTest.java
@@ -18,25 +18,25 @@
  */
 package org.jclouds.openstack.swift.blobstore.integration;
 
-import java.util.Properties;
-
 import org.jclouds.blobstore.integration.internal.BaseBlobSignerLiveTest;
 import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
 import org.testng.annotations.Test;
 
+import java.util.Properties;
+
 /**
- * 
  * @author Adrian Cole
  */
-@Test(groups = { "live" })
+@Test(groups = {"live"})
 public class SwiftBlobSignerLiveTest extends BaseBlobSignerLiveTest {
+
    @Override
    protected Properties setupProperties() {
       Properties props = super.setupProperties();
       setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
       return props;
    }
-   
+
    public SwiftBlobSignerLiveTest() {
       provider = System.getProperty("test.swift.provider", "swift");
    }
diff --git a/apis/swift/src/test/java/org/jclouds/openstack/swift/internal/StubSwiftAsyncClient.java b/apis/swift/src/test/java/org/jclouds/openstack/swift/internal/StubSwiftAsyncClient.java
index 1341de2..2d0fb15 100644
--- a/apis/swift/src/test/java/org/jclouds/openstack/swift/internal/StubSwiftAsyncClient.java
+++ b/apis/swift/src/test/java/org/jclouds/openstack/swift/internal/StubSwiftAsyncClient.java
@@ -31,6 +31,7 @@
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
+import javax.ws.rs.HeaderParam;
 
 import org.jclouds.Constants;
 import org.jclouds.blobstore.LocalAsyncBlobStore;
@@ -60,6 +61,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ListenableFuture;
+import org.jclouds.openstack.swift.reference.SwiftHeaders;
 
 /**
  * Implementation of {@link SwiftAsyncClient} which keeps all data in a local Map object.
@@ -201,7 +203,7 @@
         return null;
     }
 
-    public ListenableFuture<Boolean> setObjectInfo(String container, String key, Map<String, String> userMetadata) {
+   public ListenableFuture<Boolean> setObjectInfo(String container, String key, Map<String, String> userMetadata) {
       throw new UnsupportedOperationException();
    }
 
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/BlobRequestSigner.java b/blobstore/src/main/java/org/jclouds/blobstore/BlobRequestSigner.java
index 7720910..5cd65d1 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/BlobRequestSigner.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/BlobRequestSigner.java
@@ -18,6 +18,7 @@
  */
 package org.jclouds.blobstore;
 
+import com.google.common.annotations.Beta;
 import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.domain.BlobBuilder;
 import org.jclouds.blobstore.internal.RequestSigningUnsupported;
@@ -48,6 +49,17 @@
    HttpRequest signGetBlob(String container, String name);
 
    /**
+    * gets a signed request, including headers as necessary, to allow access to a blob
+    * from an external client for a limited period of time
+    *
+    * @param timeInSeconds
+    *           validity time in seconds for the generated request
+    * @see #signGetBlob(String, String)
+    */
+   @Beta
+   HttpRequest signGetBlob(String container, String name, long timeInSeconds);
+
+   /**
     * @param options
     * @see #signGetBlob(String, String)
     */
@@ -84,4 +96,16 @@
     * @see BlobBuilder#forSigning
     */
    HttpRequest signPutBlob(String container, Blob blob);
+
+   /**
+    * gets a signed request, including headers as necessary, to upload a blob from an
+    * external client for a limited period of time
+    *
+    * @param timeInSeconds
+    *           validity time in seconds for the generated request
+    * @see BlobBuilder#forSigning
+    * @see BlobRequestSigner#signPutBlob
+    */
+   @Beta
+   HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds);
 }
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/TransientBlobRequestSigner.java b/blobstore/src/main/java/org/jclouds/blobstore/TransientBlobRequestSigner.java
index e005ca3..9cd59a7 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/TransientBlobRequestSigner.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/TransientBlobRequestSigner.java
@@ -63,6 +63,11 @@
    }
 
    @Override
+   public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signPutBlob(String container, Blob blob) {
       HttpRequest request = HttpRequest.builder().method("PUT").endpoint(
                URI.create(String.format("%s/%s/%s", endpoint.get(), container, blob.getMetadata().getName()))).payload(
@@ -72,6 +77,11 @@
    }
 
    @Override
+   public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signRemoveBlob(String container, String name) {
       HttpRequest request = HttpRequest.builder().method("DELETE").endpoint(String.format("%s/%s/%s", endpoint.get(), container,
                name)).build();
diff --git a/blobstore/src/main/java/org/jclouds/blobstore/internal/RequestSigningUnsupported.java b/blobstore/src/main/java/org/jclouds/blobstore/internal/RequestSigningUnsupported.java
index f86ed67..cd17ebe 100644
--- a/blobstore/src/main/java/org/jclouds/blobstore/internal/RequestSigningUnsupported.java
+++ b/blobstore/src/main/java/org/jclouds/blobstore/internal/RequestSigningUnsupported.java
@@ -38,7 +38,12 @@
    }
 
    @Override
-   public HttpRequest signPutBlob(String container, Blob blob) {
+   public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public HttpRequest signGetBlob(String container, String name, GetOptions options) {
       throw new UnsupportedOperationException();
    }
 
@@ -48,7 +53,12 @@
    }
 
    @Override
-   public HttpRequest signGetBlob(String container, String name, GetOptions options) {
+   public HttpRequest signPutBlob(String container, Blob blob) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
       throw new UnsupportedOperationException();
    }
 
diff --git a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobSignerLiveTest.java b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobSignerLiveTest.java
index 200f439..bee7e72 100644
--- a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobSignerLiveTest.java
+++ b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobSignerLiveTest.java
@@ -20,42 +20,29 @@
 
 import static org.jclouds.blobstore.options.GetOptions.Builder.range;
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
 
 import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.AuthorizationException;
 import org.jclouds.util.Strings2;
+import org.testng.SkipException;
 import org.testng.annotations.Test;
 
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Tests integrated functionality of all signature commands.
  * <p/>
  * Each test uses a different container name, so it should be perfectly fine to run in parallel.
- * 
+ *
  * @author Adrian Cole
  */
-@Test(groups = { "live" })
+@Test(groups = {"live"})
 public class BaseBlobSignerLiveTest extends BaseBlobStoreIntegrationTest {
 
    @Test
-   public void testSignRemoveUrl() throws Exception {
-      String name = "hello";
-      String text = "fooooooooooooooooooooooo";
-
-      Blob blob = view.getBlobStore().blobBuilder(name).payload(text).contentType("text/plain").build();
-      String container = getContainerName();
-      try {
-         view.getBlobStore().putBlob(container, blob);
-         assertConsistencyAwareContainerSize(container, 1);
-         HttpRequest request = view.getSigner().signRemoveBlob(container, name);
-         assertEquals(request.getFilters().size(), 0);
-         view.utils().http().invoke(request);
-         assert !view.getBlobStore().blobExists(container, name);
-      } finally {
-         returnContainer(container);
-      }
-   }
-
-   @Test
    public void testSignGetUrl() throws Exception {
       String name = "hello";
       String text = "fooooooooooooooooooooooo";
@@ -92,6 +79,34 @@
    }
 
    @Test
+   public void testSignGetUrlWithTime() throws InterruptedException, IOException {
+      String name = "hello";
+      String text = "fooooooooooooooooooooooo";
+
+      Blob blob = view.getBlobStore().blobBuilder(name).payload(text).contentType("text/plain").build();
+      String container = getContainerName();
+      try {
+         view.getBlobStore().putBlob(container, blob);
+         assertConsistencyAwareContainerSize(container, 1);
+         HttpRequest request = view.getSigner().signGetBlob(container, name, 3 /* seconds */);
+
+         assertEquals(request.getFilters().size(), 0);
+         assertEquals(Strings2.toString(view.utils().http().invoke(request).getPayload()), text);
+
+         TimeUnit.SECONDS.sleep(4);
+         try {
+            Strings2.toString(view.utils().http().invoke(request).getPayload());
+            fail("Temporary URL did not expire as expected");
+         } catch (AuthorizationException expected) {
+         }
+      } catch (UnsupportedOperationException ignore) {
+         throw new SkipException("signGetUrl with a time limit is not supported on " + provider);
+      } finally {
+         returnContainer(container);
+      }
+   }
+
+   @Test
    public void testSignPutUrl() throws Exception {
       String name = "hello";
       String text = "fooooooooooooooooooooooo";
@@ -108,4 +123,52 @@
       }
    }
 
+   @Test
+   public void testSignPutUrlWithTime() throws Exception {
+      String name = "hello";
+      String text = "fooooooooooooooooooooooo";
+
+      Blob blob = view.getBlobStore().blobBuilder(name).payload(text).contentType("text/plain").build();
+      String container = getContainerName();
+      try {
+         HttpRequest request = view.getSigner().signPutBlob(container, blob, 3 /* seconds */);
+         assertEquals(request.getFilters().size(), 0);
+
+         Strings2.toString(view.utils().http().invoke(request).getPayload());
+         assertConsistencyAwareContainerSize(container, 1);
+
+         view.getBlobStore().removeBlob(container, name);
+         assertConsistencyAwareContainerSize(container, 0);
+
+         TimeUnit.SECONDS.sleep(4);
+         try {
+            Strings2.toString(view.utils().http().invoke(request).getPayload());
+            fail("Temporary URL did not expire as expected");
+         } catch (AuthorizationException expected) {
+         }
+      } catch (UnsupportedOperationException ignore) {
+         throw new SkipException("signPutUrl with a time limit is not supported on " + provider);
+      } finally {
+         returnContainer(container);
+      }
+   }
+
+   @Test
+   public void testSignRemoveUrl() throws Exception {
+      String name = "hello";
+      String text = "fooooooooooooooooooooooo";
+
+      Blob blob = view.getBlobStore().blobBuilder(name).payload(text).contentType("text/plain").build();
+      String container = getContainerName();
+      try {
+         view.getBlobStore().putBlob(container, blob);
+         assertConsistencyAwareContainerSize(container, 1);
+         HttpRequest request = view.getSigner().signRemoveBlob(container, name);
+         assertEquals(request.getFilters().size(), 0);
+         view.utils().http().invoke(request);
+         assert !view.getBlobStore().blobExists(container, name);
+      } finally {
+         returnContainer(container);
+      }
+   }
 }
\ No newline at end of file
diff --git a/common/aws/src/main/java/org/jclouds/aws/binders/BindMapToIndexedFormParams.java b/common/aws/src/main/java/org/jclouds/aws/binders/BindMapToIndexedFormParams.java
new file mode 100644
index 0000000..4d39079
--- /dev/null
+++ b/common/aws/src/main/java/org/jclouds/aws/binders/BindMapToIndexedFormParams.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.aws.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.String.format;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+
+/**
+ * @author Adrian Cole
+ */
+public class BindMapToIndexedFormParams implements Binder {
+
+   private final String keyPattern;
+   private final String valuePattern;
+
+   protected BindMapToIndexedFormParams(String keyPattern, String valuePattern) {
+      this.keyPattern = keyPattern;
+      this.valuePattern = valuePattern;
+   }
+
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      if (checkNotNull(input, "input") instanceof Iterable)
+         input = Maps.uniqueIndex((Iterable<String>) input, new Function<String, String>() {
+            int index = 1;
+
+            @Override
+            public String apply(String input) {
+               return index++ + "";
+            }
+         });
+      checkArgument(checkNotNull(input, "input") instanceof Map, "this binder is only valid for Map");
+      Map<String, String> mapping = (Map<String, String>) input;
+
+      ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+      int amazonOneBasedIndex = 1; // according to docs, counters must start
+                                   // with 1
+      for (Entry<String, String> entry : mapping.entrySet()) {
+         // not null by contract
+         builder.put(format(keyPattern, amazonOneBasedIndex), entry.getKey());
+         builder.put(format(valuePattern, amazonOneBasedIndex), entry.getValue());
+         amazonOneBasedIndex++;
+      }
+      Multimap<String, String> forms = Multimaps.forMap(builder.build());
+      return forms.size() == 0 ? request : (R) request.toBuilder().replaceFormParams(forms).build();
+   }
+
+}
diff --git a/common/aws/src/main/java/org/jclouds/aws/binders/BindTableToIndexedFormParams.java b/common/aws/src/main/java/org/jclouds/aws/binders/BindTableToIndexedFormParams.java
new file mode 100644
index 0000000..3d0d91d
--- /dev/null
+++ b/common/aws/src/main/java/org/jclouds/aws/binders/BindTableToIndexedFormParams.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.aws.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.lang.String.format;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.ImmutableTable.Builder;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Table;
+import com.google.common.collect.Table.Cell;
+
+/**
+ * @author Adrian Cole
+ */
+public class BindTableToIndexedFormParams implements Binder {
+
+   private final String rowPattern;
+   private final String columnPattern;
+   private final String valuePattern;
+
+   protected BindTableToIndexedFormParams(String rowPattern, String columnPattern, String valuePattern) {
+      this.rowPattern = rowPattern;
+      this.columnPattern = columnPattern;
+      this.valuePattern = valuePattern;
+   }
+
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      if (checkNotNull(input, "input") instanceof Map) {
+         Builder<Object, Object, Object> builder = ImmutableTable.builder();
+         int index = 1;
+         for (Map.Entry<?, ?> entry : ((Map<?, ?>) input).entrySet())
+            builder.put(index++, entry.getKey(), entry.getValue());
+         input = builder.build();
+      }
+      checkArgument(checkNotNull(input, "input") instanceof Table, "this binder is only valid for Table");
+      Table<?, ?, ?> table = Table.class.cast(input);
+
+      ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+      int amazonOneBasedIndex = 1; // according to docs, counters must start
+                                   // with 1
+      for (Cell<?, ?, ?> cell : table.cellSet()) {
+         // not null by contract
+         builder.put(format(rowPattern, amazonOneBasedIndex), cell.getRowKey().toString());
+         builder.put(format(columnPattern, amazonOneBasedIndex), cell.getColumnKey().toString());
+         builder.put(format(valuePattern, amazonOneBasedIndex), cell.getValue().toString());
+
+         amazonOneBasedIndex++;
+      }
+      Multimap<String, String> forms = Multimaps.forMap(builder.build());
+      return forms.size() == 0 ? request : (R) request.toBuilder().replaceFormParams(forms).build();
+   }
+
+}
diff --git a/common/aws/src/main/java/org/jclouds/aws/config/AWSRestClientModule.java b/common/aws/src/main/java/org/jclouds/aws/config/AWSRestClientModule.java
index 7915b4f..75b4cb5 100644
--- a/common/aws/src/main/java/org/jclouds/aws/config/AWSRestClientModule.java
+++ b/common/aws/src/main/java/org/jclouds/aws/config/AWSRestClientModule.java
@@ -20,6 +20,9 @@
 
 
 import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Singleton;
 
 import org.jclouds.aws.handlers.AWSClientErrorRetryHandler;
 import org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent;
@@ -31,7 +34,9 @@
 import org.jclouds.rest.ConfiguresRestClient;
 import org.jclouds.rest.config.RestClientModule;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.reflect.TypeToken;
+import com.google.inject.Provides;
 
 
 /**
@@ -57,6 +62,13 @@
       super(syncClientType, asyncClientType, sync2Async);
    }
    
+   @Provides
+   @ClientError
+   @Singleton
+   protected Set<String> provideRetryableCodes(){
+      return ImmutableSet.of("RequestTimeout", "OperationAborted", "SignatureDoesNotMatch");
+   }
+   
    @Override
    protected void bindErrorHandlers() {
       bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseAWSErrorFromXmlContent.class);
diff --git a/common/aws/src/main/java/org/jclouds/aws/handlers/AWSClientErrorRetryHandler.java b/common/aws/src/main/java/org/jclouds/aws/handlers/AWSClientErrorRetryHandler.java
index f074f99..b99f8b0 100644
--- a/common/aws/src/main/java/org/jclouds/aws/handlers/AWSClientErrorRetryHandler.java
+++ b/common/aws/src/main/java/org/jclouds/aws/handlers/AWSClientErrorRetryHandler.java
@@ -20,14 +20,16 @@
 
 import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
 
+import java.util.Set;
+
 import org.jclouds.aws.domain.AWSError;
 import org.jclouds.aws.util.AWSUtils;
 import org.jclouds.http.HttpCommand;
 import org.jclouds.http.HttpResponse;
 import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.annotation.ClientError;
 import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
 
-import com.google.common.collect.ImmutableSet;
 import com.google.inject.Inject;
 
 /**
@@ -39,27 +41,35 @@
 
    private final AWSUtils utils;
    private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
+   private final Set<String> retryableCodes;
 
    @Inject
-   public AWSClientErrorRetryHandler(AWSUtils utils, BackoffLimitedRetryHandler backoffLimitedRetryHandler) {
+   public AWSClientErrorRetryHandler(AWSUtils utils, BackoffLimitedRetryHandler backoffLimitedRetryHandler,
+         @ClientError Set<String> retryableCodes) {
       this.utils = utils;
       this.backoffLimitedRetryHandler = backoffLimitedRetryHandler;
+      this.retryableCodes = retryableCodes;
    }
 
+   @Override
    public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
       if (response.getStatusCode() == 400 || response.getStatusCode() == 403 || response.getStatusCode() == 409) {
          // Content can be null in the case of HEAD requests
          if (response.getPayload() != null) {
             closeClientButKeepContentStream(response);
             AWSError error = utils.parseAWSErrorFromContent(command.getCurrentRequest(), response);
-            if (error != null
-                     && ImmutableSet.of("RequestTimeout", "OperationAborted", "SignatureDoesNotMatch").contains(
-                              error.getCode())) {
-               return backoffLimitedRetryHandler.shouldRetryRequest(command, response);
+            if (error != null) {
+               return shouldRetryRequestOnError(command, response, error);
             }
          }
       }
       return false;
    }
 
+   protected boolean shouldRetryRequestOnError(HttpCommand command, HttpResponse response, AWSError error) {
+      if (retryableCodes.contains(error.getCode()))
+         return backoffLimitedRetryHandler.shouldRetryRequest(command, response);
+      return false;
+   }
+
 }
diff --git a/common/aws/src/test/java/org/jclouds/aws/handlers/AWSClientErrorRetryHandlerTest.java b/common/aws/src/test/java/org/jclouds/aws/handlers/AWSClientErrorRetryHandlerTest.java
index 03d978f..2d2ab66 100644
--- a/common/aws/src/test/java/org/jclouds/aws/handlers/AWSClientErrorRetryHandlerTest.java
+++ b/common/aws/src/test/java/org/jclouds/aws/handlers/AWSClientErrorRetryHandlerTest.java
@@ -33,6 +33,8 @@
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableSet;
+
 /**
  * Tests behavior of {@code AWSClientErrorRetryHandler}
  * 
@@ -49,7 +51,8 @@
 
       replay(utils, backoffLimitedRetryHandler, command);
 
-      AWSClientErrorRetryHandler retry = new AWSClientErrorRetryHandler(utils, backoffLimitedRetryHandler);
+      AWSClientErrorRetryHandler retry = new AWSClientErrorRetryHandler(utils, backoffLimitedRetryHandler,
+            ImmutableSet.<String> of());
 
       assert !retry.shouldRetryRequest(command, HttpResponse.builder().statusCode(401).build());
 
@@ -70,10 +73,10 @@
       HttpCommand command = createMock(HttpCommand.class);
 
       HttpRequest putBucket = HttpRequest.builder().method("PUT")
-               .endpoint("https://adriancole-blobstore113.s3.amazonaws.com/").build();
+            .endpoint("https://adriancole-blobstore113.s3.amazonaws.com/").build();
 
       HttpResponse operationAborted = HttpResponse.builder().statusCode(409)
-               .payload(Payloads.newStringPayload(String.format("<Error><Code>%s</Code></Error>", code))).build();
+            .payload(Payloads.newStringPayload(String.format("<Error><Code>%s</Code></Error>", code))).build();
 
       expect(command.getCurrentRequest()).andReturn(putBucket);
 
@@ -86,7 +89,8 @@
 
       replay(utils, backoffLimitedRetryHandler, command);
 
-      AWSClientErrorRetryHandler retry = new AWSClientErrorRetryHandler(utils, backoffLimitedRetryHandler);
+      AWSClientErrorRetryHandler retry = new AWSClientErrorRetryHandler(utils, backoffLimitedRetryHandler,
+            ImmutableSet.<String> of("RequestTimeout", "OperationAborted", "SignatureDoesNotMatch"));
 
       assert retry.shouldRetryRequest(command, operationAborted);
 
diff --git a/compute/src/test/java/org/jclouds/compute/internal/BaseComputeServiceLiveTest.java b/compute/src/test/java/org/jclouds/compute/internal/BaseComputeServiceLiveTest.java
index 7c6624a..0f26611 100644
--- a/compute/src/test/java/org/jclouds/compute/internal/BaseComputeServiceLiveTest.java
+++ b/compute/src/test/java/org/jclouds/compute/internal/BaseComputeServiceLiveTest.java
@@ -348,8 +348,8 @@
       // credentials aren't always the same
       // assertEquals(node1.getCredentials(), node2.getCredentials());
 
-      assertLocationSameOrChild(node1.getLocation(), template.getLocation());
-      assertLocationSameOrChild(node2.getLocation(), template.getLocation());
+      assertLocationSameOrChild(checkNotNull(node1.getLocation(), "location of %s", node1), template.getLocation());
+      assertLocationSameOrChild(checkNotNull(node2.getLocation(), "location of %s", node2), template.getLocation());
       checkImageIdMatchesTemplate(node1);
       checkImageIdMatchesTemplate(node2);
       checkOsMatchesTemplate(node1);
@@ -411,7 +411,7 @@
       if (existingLocationIsAssignable)
          assertEquals(node.getLocation(), existingLocation);
       else
-         this.assertLocationSameOrChild(node.getLocation(), template.getLocation());
+         this.assertLocationSameOrChild(checkNotNull(node.getLocation(), "location of %s", node), template.getLocation());
       checkOsMatchesTemplate(node);
       this.nodes.add(node);
    }
@@ -502,7 +502,7 @@
          NodeMetadata metadata = client.getNodeMetadata(node.getId());
          assertEquals(metadata.getProviderId(), node.getProviderId());
          assertEquals(metadata.getGroup(), node.getGroup());
-         assertLocationSameOrChild(metadata.getLocation(), template.getLocation());
+         assertLocationSameOrChild(checkNotNull(metadata.getLocation(), "location of %s", metadata), template.getLocation());
          checkImageIdMatchesTemplate(metadata);
          checkOsMatchesTemplate(metadata);
          assert (metadata.getStatus() == Status.RUNNING) : metadata;
@@ -645,7 +645,9 @@
    }
 
    protected void createAndRunAServiceInGroup(String group) throws RunNodesException {
-      ImmutableMap<String, String> userMetadata = ImmutableMap.<String, String> of("Name", group);
+      // note that some cloud providers do not support mixed case tag names
+      ImmutableMap<String, String> userMetadata = ImmutableMap.<String, String> of("name", group);
+      
       ImmutableSet<String> tags = ImmutableSet. of(group);
       Stopwatch watch = new Stopwatch().start();
       NodeMetadata node = getOnlyElement(client.createNodesInGroup(group, 1,
diff --git a/core/src/main/java/org/jclouds/collect/IterableWithMarkers.java b/core/src/main/java/org/jclouds/collect/IterableWithMarkers.java
index f842112..bcb1f5c 100644
--- a/core/src/main/java/org/jclouds/collect/IterableWithMarkers.java
+++ b/core/src/main/java/org/jclouds/collect/IterableWithMarkers.java
@@ -26,6 +26,7 @@
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Utilities for using {@link IterableWithMarker}s.
@@ -34,6 +35,9 @@
  */
 @Beta
 public class IterableWithMarkers {
+   
+   @SuppressWarnings("rawtypes")
+   public static final IterableWithMarker EMPTY = from(ImmutableSet.of());
 
    /**
     * Returns a paginated iterable containing the given elements and null marker.
diff --git a/core/src/main/java/org/jclouds/collect/PagedIterables.java b/core/src/main/java/org/jclouds/collect/PagedIterables.java
index b98c038..87988bc 100644
--- a/core/src/main/java/org/jclouds/collect/PagedIterables.java
+++ b/core/src/main/java/org/jclouds/collect/PagedIterables.java
@@ -35,6 +35,17 @@
  */
 @Beta
 public class PagedIterables {
+   
+   @SuppressWarnings("rawtypes")
+   public static final PagedIterable EMPTY = new PagedIterable() {
+
+      @Override
+      public Iterator<IterableWithMarker> iterator() {
+         return ImmutableSet.of(IterableWithMarkers.EMPTY).iterator();
+      }
+
+   };
+   
    /**
     * @param only
     *           the only page of data
diff --git a/core/src/main/java/org/jclouds/json/config/GsonModule.java b/core/src/main/java/org/jclouds/json/config/GsonModule.java
index 8d273c5..fa2728f 100644
--- a/core/src/main/java/org/jclouds/json/config/GsonModule.java
+++ b/core/src/main/java/org/jclouds/json/config/GsonModule.java
@@ -39,6 +39,8 @@
 import org.jclouds.json.internal.DeserializationConstructorAndReflectiveTypeAdapterFactory;
 import org.jclouds.json.internal.EnumTypeAdapterThatReturnsFromValue;
 import org.jclouds.json.internal.GsonWrapper;
+import org.jclouds.json.internal.IgnoreNullFluentIterableTypeAdapterFactory;
+import org.jclouds.json.internal.IgnoreNullIterableTypeAdapterFactory;
 import org.jclouds.json.internal.IgnoreNullMapTypeAdapterFactory;
 import org.jclouds.json.internal.IgnoreNullMultimapTypeAdapterFactory;
 import org.jclouds.json.internal.IgnoreNullSetTypeAdapterFactory;
@@ -81,7 +83,10 @@
    @Provides
    @Singleton
    Gson provideGson(TypeAdapter<JsonBall> jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter,
-            ByteArrayAdapter byteArrayAdapter, PropertiesAdapter propertiesAdapter, JsonAdapterBindings bindings)
+            ByteArrayAdapter byteArrayAdapter, PropertiesAdapter propertiesAdapter, JsonAdapterBindings bindings,
+            OptionalTypeAdapterFactory optional, IgnoreNullSetTypeAdapterFactory set,
+            IgnoreNullMapTypeAdapterFactory map, IgnoreNullMultimapTypeAdapterFactory multimap,
+            IgnoreNullIterableTypeAdapterFactory iterable, IgnoreNullFluentIterableTypeAdapterFactory fluentIterable)
             throws Exception {
 
       FieldNamingStrategy serializationPolicy = new AnnotationOrNameFieldNamingStrategy(new ExtractSerializedName(),
@@ -96,10 +101,12 @@
       }.getType(), byteListAdapter.nullSafe());
       builder.registerTypeAdapter(byte[].class, byteArrayAdapter.nullSafe());
       builder.registerTypeAdapter(JsonBall.class, jsonAdapter.nullSafe());
-      builder.registerTypeAdapterFactory(new OptionalTypeAdapterFactory());
-      builder.registerTypeAdapterFactory(new IgnoreNullSetTypeAdapterFactory());
-      builder.registerTypeAdapterFactory(new IgnoreNullMapTypeAdapterFactory());
-      builder.registerTypeAdapterFactory(new IgnoreNullMultimapTypeAdapterFactory());
+      builder.registerTypeAdapterFactory(optional);
+      builder.registerTypeAdapterFactory(iterable);
+      builder.registerTypeAdapterFactory(set);
+      builder.registerTypeAdapterFactory(map);
+      builder.registerTypeAdapterFactory(multimap);
+      builder.registerTypeAdapterFactory(fluentIterable);
 
       AnnotationConstructorNamingStrategy deserializationPolicy =
             new AnnotationConstructorNamingStrategy(
diff --git a/core/src/main/java/org/jclouds/json/internal/IgnoreNullFluentIterableTypeAdapterFactory.java b/core/src/main/java/org/jclouds/json/internal/IgnoreNullFluentIterableTypeAdapterFactory.java
new file mode 100644
index 0000000..42d31e2
--- /dev/null
+++ b/core/src/main/java/org/jclouds/json/internal/IgnoreNullFluentIterableTypeAdapterFactory.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.json.internal;
+
+import java.io.IOException;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+/**
+ * Eliminates null values when deserializing FluentIterables
+ * <p/>
+ * Treats [null] as the empty set; [A, null] as [A]; etc.
+ * 
+ * @author Adam Lowe
+ */
+public class IgnoreNullFluentIterableTypeAdapterFactory implements TypeAdapterFactory {
+   
+   @SuppressWarnings("unchecked")
+   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
+      Type type = typeToken.getType();
+      if (typeToken.getRawType() != FluentIterable.class || !(type instanceof ParameterizedType)) {
+         return null;
+      }
+
+      Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
+      TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
+      return (TypeAdapter<T>) newFluentIterableAdapter(elementAdapter);
+   }
+
+   protected <E> TypeAdapter<FluentIterable<E>> newFluentIterableAdapter(final TypeAdapter<E> elementAdapter) {
+      return new TypeAdapter<FluentIterable<E>>() {
+         public void write(JsonWriter out, FluentIterable<E> value) throws IOException {
+            out.beginArray();
+            for (E element : value) {
+               elementAdapter.write(out, element);
+            }
+            out.endArray();
+         }
+
+         public FluentIterable<E> read(JsonReader in) throws IOException {
+                                                                 in.beginArray();
+            Builder<E> builder = ImmutableList.<E>builder();
+            while (in.hasNext()) {
+               E element = elementAdapter.read(in);
+               if (element != null) builder.add(element);
+            }
+            in.endArray();
+            return FluentIterable.from(builder.build());
+         }
+      }.nullSafe();
+   }
+}
diff --git a/core/src/main/java/org/jclouds/json/internal/IgnoreNullIterableTypeAdapterFactory.java b/core/src/main/java/org/jclouds/json/internal/IgnoreNullIterableTypeAdapterFactory.java
new file mode 100644
index 0000000..f4c88fb
--- /dev/null
+++ b/core/src/main/java/org/jclouds/json/internal/IgnoreNullIterableTypeAdapterFactory.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.json.internal;
+
+import java.io.IOException;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+/**
+ * Eliminates null values when deserializing Iterables
+ * <p/>
+ * Treats [null] as the empty set; [A, null] as [A]; etc.
+ * 
+ * @author Adam Lowe
+ */
+public class IgnoreNullIterableTypeAdapterFactory implements TypeAdapterFactory {
+   
+   @SuppressWarnings("unchecked")
+   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
+      Type type = typeToken.getType();
+      if (typeToken.getRawType() != Iterable.class || !(type instanceof ParameterizedType)) {
+         return null;
+      }
+
+      Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
+      TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
+      return (TypeAdapter<T>) newIterableAdapter(elementAdapter);
+   }
+
+   protected <E> TypeAdapter<Iterable<E>> newIterableAdapter(final TypeAdapter<E> elementAdapter) {
+      return new TypeAdapter<Iterable<E>>() {
+         public void write(JsonWriter out, Iterable<E> value) throws IOException {
+            out.beginArray();
+            for (E element : value) {
+               elementAdapter.write(out, element);
+            }
+            out.endArray();
+         }
+
+         public Iterable<E> read(JsonReader in) throws IOException {
+            in.beginArray();
+            Builder<E> builder = ImmutableList.<E>builder();
+            while (in.hasNext()) {
+               E element = elementAdapter.read(in);
+               if (element != null) builder.add(element);
+            }
+            in.endArray();
+            return builder.build();
+         }
+      }.nullSafe();
+   }
+}
diff --git a/core/src/main/java/org/jclouds/json/internal/IgnoreNullMapTypeAdapterFactory.java b/core/src/main/java/org/jclouds/json/internal/IgnoreNullMapTypeAdapterFactory.java
index 7fcfb2b..71d032f 100644
--- a/core/src/main/java/org/jclouds/json/internal/IgnoreNullMapTypeAdapterFactory.java
+++ b/core/src/main/java/org/jclouds/json/internal/IgnoreNullMapTypeAdapterFactory.java
@@ -54,7 +54,7 @@
       return (TypeAdapter<T>) newMapAdapter(keyAdapter, valueAdapter);
    }
 
-   private <K,V> TypeAdapter<Map<K, V>> newMapAdapter(final TypeAdapter<K> keyAdapter, final TypeAdapter<V> valueAdapter) {
+   protected <K,V> TypeAdapter<Map<K, V>> newMapAdapter(final TypeAdapter<K> keyAdapter, final TypeAdapter<V> valueAdapter) {
       return new TypeAdapter<Map<K, V>>() {
          public void write(JsonWriter out, Map<K, V> value) throws IOException {
             out.beginObject();
diff --git a/core/src/main/java/org/jclouds/json/internal/IgnoreNullMultimapTypeAdapterFactory.java b/core/src/main/java/org/jclouds/json/internal/IgnoreNullMultimapTypeAdapterFactory.java
index 77938bd..6a2827c 100644
--- a/core/src/main/java/org/jclouds/json/internal/IgnoreNullMultimapTypeAdapterFactory.java
+++ b/core/src/main/java/org/jclouds/json/internal/IgnoreNullMultimapTypeAdapterFactory.java
@@ -51,10 +51,10 @@
       Type valueType = ((ParameterizedType) type).getActualTypeArguments()[1];
       TypeAdapter<?> keyAdapter = gson.getAdapter(TypeToken.get(keyType));
       TypeAdapter<?> valueAdapter = gson.getAdapter(TypeToken.get(valueType));
-      return (TypeAdapter<T>) newMapAdapter(keyAdapter, valueAdapter);
+      return (TypeAdapter<T>) newMultimapAdapter(keyAdapter, valueAdapter);
    }
 
-   private <K,V> TypeAdapter<Multimap<K, V>> newMapAdapter(final TypeAdapter<K> keyAdapter, final TypeAdapter<V> valueAdapter) {
+   protected <K,V> TypeAdapter<Multimap<K, V>> newMultimapAdapter(final TypeAdapter<K> keyAdapter, final TypeAdapter<V> valueAdapter) {
       return new TypeAdapter<Multimap<K, V>>() {
          public void write(JsonWriter out, Multimap<K, V> map) throws IOException {
             out.beginObject();
diff --git a/core/src/main/java/org/jclouds/json/internal/IgnoreNullSetTypeAdapterFactory.java b/core/src/main/java/org/jclouds/json/internal/IgnoreNullSetTypeAdapterFactory.java
index 393a710..1ae22c3 100644
--- a/core/src/main/java/org/jclouds/json/internal/IgnoreNullSetTypeAdapterFactory.java
+++ b/core/src/main/java/org/jclouds/json/internal/IgnoreNullSetTypeAdapterFactory.java
@@ -23,7 +23,7 @@
 import java.lang.reflect.Type;
 import java.util.Set;
 
-import com.google.common.collect.Sets;
+import com.google.common.collect.ImmutableSet;
 import com.google.gson.Gson;
 import com.google.gson.TypeAdapter;
 import com.google.gson.TypeAdapterFactory;
@@ -32,7 +32,7 @@
 import com.google.gson.stream.JsonWriter;
 
 /**
- * Eliminates null values when deserializing Sets
+ * Eliminates null values when deserializing Sets.
  * <p/>
  * Treats [null] as the empty set; [A, null] as [A]; etc.
  * 
@@ -52,7 +52,7 @@
       return (TypeAdapter<T>) newSetAdapter(elementAdapter);
    }
 
-   private <E> TypeAdapter<Set<E>> newSetAdapter(final TypeAdapter<E> elementAdapter) {
+   protected <E> TypeAdapter<Set<E>> newSetAdapter(final TypeAdapter<E> elementAdapter) {
       return new TypeAdapter<Set<E>>() {
          public void write(JsonWriter out, Set<E> value) throws IOException {
             out.beginArray();
@@ -63,14 +63,15 @@
          }
 
          public Set<E> read(JsonReader in) throws IOException {
-            Set<E> result = Sets.newLinkedHashSet();
+            ImmutableSet.Builder<E> result = ImmutableSet.<E> builder();
             in.beginArray();
             while (in.hasNext()) {
                E element = elementAdapter.read(in);
-               if (element != null) result.add(element);
+               if (element != null)
+                  result.add(element);
             }
             in.endArray();
-            return result;
+            return result.build();
          }
       }.nullSafe();
    }
diff --git a/core/src/main/java/org/jclouds/json/internal/OptionalTypeAdapterFactory.java b/core/src/main/java/org/jclouds/json/internal/OptionalTypeAdapterFactory.java
index 1855e8e..0e57f8e 100644
--- a/core/src/main/java/org/jclouds/json/internal/OptionalTypeAdapterFactory.java
+++ b/core/src/main/java/org/jclouds/json/internal/OptionalTypeAdapterFactory.java
@@ -48,10 +48,10 @@
 
       Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
       TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
-      return (TypeAdapter<T>) newMultisetAdapter(elementAdapter);
+      return (TypeAdapter<T>) newOptionalAdapter(elementAdapter);
    }
 
-   private <E> TypeAdapter<Optional<E>> newMultisetAdapter(
+   protected <E> TypeAdapter<Optional<E>> newOptionalAdapter(
          final TypeAdapter<E> elementAdapter) {
       return new TypeAdapter<Optional<E>>() {
          public void write(JsonWriter out, Optional<E> value) throws IOException {
diff --git a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyFluentIterableOnNotFoundOr404.java b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyFluentIterableOnNotFoundOr404.java
new file mode 100644
index 0000000..b2711c5
--- /dev/null
+++ b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyFluentIterableOnNotFoundOr404.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.rest.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.functions.ReturnTrueOn404;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Singleton
+public class ReturnEmptyFluentIterableOnNotFoundOr404 implements Function<Exception, Object> {
+   private final ReturnTrueOn404 rto404;
+
+   @Inject
+   private ReturnEmptyFluentIterableOnNotFoundOr404(ReturnTrueOn404 rto404) {
+      this.rto404 = checkNotNull(rto404, "rto404");
+   }
+
+   public Object apply(Exception from) {
+      Iterable<ResourceNotFoundException> throwables = Iterables.filter(Throwables.getCausalChain(from),
+               ResourceNotFoundException.class);
+      if (Iterables.size(throwables) >= 1) {
+         return FluentIterable.from(ImmutableSet.of());
+      } else if (rto404.apply(from)) {
+         return FluentIterable.from(ImmutableSet.of());
+      }
+      throw Throwables.propagate(from);
+   }
+
+}
diff --git a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyIterableWithMarkerOnNotFoundOr404.java b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyIterableWithMarkerOnNotFoundOr404.java
new file mode 100644
index 0000000..ff5cbea
--- /dev/null
+++ b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyIterableWithMarkerOnNotFoundOr404.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.rest.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarkers;
+import org.jclouds.http.functions.ReturnTrueOn404;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Singleton
+public class ReturnEmptyIterableWithMarkerOnNotFoundOr404 implements Function<Exception, Object> {
+   private final ReturnTrueOn404 rto404;
+
+   @Inject
+   private ReturnEmptyIterableWithMarkerOnNotFoundOr404(ReturnTrueOn404 rto404) {
+      this.rto404 = checkNotNull(rto404, "rto404");
+   }
+
+   public Object apply(Exception from) {
+      Iterable<ResourceNotFoundException> throwables = Iterables.filter(Throwables.getCausalChain(from),
+               ResourceNotFoundException.class);
+      if (Iterables.size(throwables) >= 1) {
+         return IterableWithMarkers.EMPTY;
+      } else if (rto404.apply(from)) {
+         return IterableWithMarkers.EMPTY;
+      }
+      throw Throwables.propagate(from);
+   }
+
+}
diff --git a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyListOnNotFoundOr404.java b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyListOnNotFoundOr404.java
index e7ad30a..46ed693 100644
--- a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyListOnNotFoundOr404.java
+++ b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyListOnNotFoundOr404.java
@@ -20,8 +20,6 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.util.List;
-
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
diff --git a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyMapOnNotFoundOr404.java b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyMapOnNotFoundOr404.java
index 156abab..50f37c9 100644
--- a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyMapOnNotFoundOr404.java
+++ b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyMapOnNotFoundOr404.java
@@ -20,8 +20,6 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.util.Map;
-
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
diff --git a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyMultimapOnNotFoundOr404.java b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyMultimapOnNotFoundOr404.java
index 763190c..9f365d1 100644
--- a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyMultimapOnNotFoundOr404.java
+++ b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyMultimapOnNotFoundOr404.java
@@ -30,7 +30,6 @@
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimap;
 
 /**
  * 
diff --git a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyPagedIterableOnNotFoundOr404.java b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyPagedIterableOnNotFoundOr404.java
new file mode 100644
index 0000000..48905ab
--- /dev/null
+++ b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptyPagedIterableOnNotFoundOr404.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.rest.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.PagedIterables;
+import org.jclouds.http.functions.ReturnTrueOn404;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Singleton
+public class ReturnEmptyPagedIterableOnNotFoundOr404 implements Function<Exception, Object> {
+   private final ReturnTrueOn404 rto404;
+
+   @Inject
+   private ReturnEmptyPagedIterableOnNotFoundOr404(ReturnTrueOn404 rto404) {
+      this.rto404 = checkNotNull(rto404, "rto404");
+   }
+
+   public Object apply(Exception from) {
+      Iterable<ResourceNotFoundException> throwables = Iterables.filter(Throwables.getCausalChain(from),
+               ResourceNotFoundException.class);
+      if (Iterables.size(throwables) >= 1) {
+         return PagedIterables.EMPTY;
+      } else if (rto404.apply(from)) {
+         return PagedIterables.EMPTY;
+      }
+      throw Throwables.propagate(from);
+   }
+
+}
diff --git a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptySetOnNotFoundOr404.java b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptySetOnNotFoundOr404.java
index cdd6615..b8be87e 100644
--- a/core/src/main/java/org/jclouds/rest/functions/ReturnEmptySetOnNotFoundOr404.java
+++ b/core/src/main/java/org/jclouds/rest/functions/ReturnEmptySetOnNotFoundOr404.java
@@ -20,8 +20,6 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.util.Set;
-
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
diff --git a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java
index 215821a..1a8376e 100644
--- a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java
+++ b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java
@@ -140,6 +140,7 @@
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
 import com.google.common.base.Objects;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
@@ -1014,7 +1015,7 @@
 
             Annotation[] annotations = request.getJavaMethod().getParameterAnnotations()[entry.getKey()];
             for (Annotation a : annotations) {
-               if (Nullable.class.isAssignableFrom(a.annotationType()))
+               if (NULLABLE.apply(a))
                   continue OUTER;
             }
             Preconditions.checkNotNull(null, request.getJavaMethod().getName() + " parameter " + (entry.getKey() + 1));
@@ -1188,17 +1189,11 @@
          for (Annotation key : entry.getValue()) {
             Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
             String paramKey = ((PathParam) key).value();
-            String paramValue;
-            if (extractors != null && extractors.size() > 0) {
-               ParamParser extractor = (ParamParser) extractors.iterator().next();
-               paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
-            } else {
-               paramValue = args[entry.getKey()].toString();
-            }
-            pathParamValues.put(paramKey, paramValue);
+            Optional<?> paramValue = getParamValue(method, args, extractors, entry, paramKey);
+            if (paramValue.isPresent())
+               pathParamValues.put(paramKey, paramValue.get().toString());
          }
       }
-
       if (method.isAnnotationPresent(PathParam.class) && method.isAnnotationPresent(ParamParser.class)) {
          String paramKey = method.getAnnotation(PathParam.class).value();
          String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value()).apply(args);
@@ -1208,6 +1203,42 @@
       return pathParamValues;
    }
 
+   protected Optional<?> getParamValue(Method method, Object[] args, Set<Annotation> extractors,
+            Entry<Integer, Set<Annotation>> entry, String paramKey) {
+      Integer argIndex = entry.getKey();
+      Object arg = args[argIndex];
+      if (extractors != null && extractors.size() > 0 && checkPresentOrNullable(method, paramKey, argIndex, arg)) {
+         ParamParser extractor = (ParamParser) extractors.iterator().next();
+         // ParamParsers can deal with nullable parameters
+         arg = injector.getInstance(extractor.value()).apply(arg);
+      }
+      checkPresentOrNullable(method, paramKey, argIndex, arg);
+      return Optional.fromNullable(arg);
+   }
+
+   private static boolean checkPresentOrNullable(Method method, String paramKey, Integer argIndex, Object arg) {
+      if (arg == null && !argNullable(method, argIndex))
+         throw new NullPointerException(String.format("param{%s} for method %s.%s", paramKey, method
+                  .getDeclaringClass().getSimpleName(), method.getName()));
+      return true;
+   }
+
+   private static boolean argNullable(Method method, Integer argIndex) {
+      return containsNullable(method.getParameterAnnotations()[argIndex]);
+   }
+
+   private static final Predicate<Annotation> NULLABLE = new Predicate<Annotation>() {
+
+      @Override
+      public boolean apply(Annotation in) {
+         return Nullable.class.isAssignableFrom(in.annotationType());
+      }
+   };
+
+   private static boolean containsNullable(Annotation[] annotations) {
+      return Iterables.any(ImmutableSet.copyOf(annotations), NULLABLE);
+   }
+
    private Multimap<String, String> encodeValues(Multimap<String, String> unencoded, char... skips) {
       Multimap<String, String> encoded = LinkedHashMultimap.create();
       for (Entry<String, String> entry : unencoded.entries()) {
@@ -1226,14 +1257,9 @@
          for (Annotation key : entry.getValue()) {
             Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
             String paramKey = ((MatrixParam) key).value();
-            String paramValue;
-            if (extractors != null && extractors.size() > 0) {
-               ParamParser extractor = (ParamParser) extractors.iterator().next();
-               paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
-            } else {
-               paramValue = args[entry.getKey()].toString();
-            }
-            matrixParamValues.put(paramKey, paramValue);
+            Optional<?> paramValue = getParamValue(method, args, extractors, entry, paramKey);
+            if (paramValue.isPresent())
+               matrixParamValues.put(paramKey, paramValue.get().toString());
          }
       }
 
@@ -1257,16 +1283,9 @@
          for (Annotation key : entry.getValue()) {
             Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
             String paramKey = ((FormParam) key).value();
-            String paramValue;
-            if (extractors != null && extractors.size() > 0) {
-               ParamParser extractor = (ParamParser) extractors.iterator().next();
-               paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
-            } else {
-               Object pvo = args[entry.getKey()];
-               Preconditions.checkNotNull(pvo, paramKey);
-               paramValue = pvo.toString();
-            }
-            formParamValues.put(paramKey, paramValue);
+            Optional<?> paramValue = getParamValue(method, args, extractors, entry, paramKey);
+            if (paramValue.isPresent())
+               formParamValues.put(paramKey, paramValue.get().toString());
          }
       }
 
@@ -1289,16 +1308,9 @@
          for (Annotation key : entry.getValue()) {
             Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
             String paramKey = ((QueryParam) key).value();
-            Object paramValue;
-            if (extractors != null && extractors.size() > 0) {
-               ParamParser extractor = (ParamParser) extractors.iterator().next();
-               paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
-            } else {
-               paramValue = args[entry.getKey()];
-            }
-            if (paramValue != null) {
-                queryParamValues.put(paramKey, paramValue.toString());
-            }
+            Optional<?> paramValue = getParamValue(method, args, extractors, entry, paramKey);
+            if (paramValue.isPresent())
+               queryParamValues.put(paramKey, paramValue.get().toString());
          }
       }
 
@@ -1321,15 +1333,9 @@
          for (Annotation key : entry.getValue()) {
             Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
             String paramKey = ((PayloadParam) key).value();
-            Object paramValue;
-            if (extractors != null && extractors.size() > 0) {
-               ParamParser extractor = (ParamParser) extractors.iterator().next();
-               paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
-            } else {
-               paramValue = args[entry.getKey()] != null ? args[entry.getKey()] : null;
-            }
-            postParams.put(paramKey, paramValue);
-
+            Optional<?> paramValue = getParamValue(method, args, extractors, entry, paramKey);
+            if (paramValue.isPresent())
+               postParams.put(paramKey, paramValue.get());
          }
       }
       return postParams;
diff --git a/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java b/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java
index f14de94..0bce56f 100644
--- a/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java
+++ b/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java
@@ -499,6 +499,12 @@
       @QueryParams(keys = { "foo", "fooble" }, values = { "bar", "baz" })
       public void foo3(@QueryParam("robbie") String robbie) {
       }
+      
+      @FOO
+      @Path("/")
+      @QueryParams(keys = { "foo", "fooble" }, values = { "bar", "baz" })
+      public void foo3Nullable(@Nullable @QueryParam("robbie") String robbie) {
+      }
    }
 
    public void testUnEncodeQuery() {
@@ -537,6 +543,25 @@
       assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17&foo=bar&fooble=baz&robbie=wonder");
       assertEquals(request.getMethod(), "FOO");
    }
+   
+   @Test
+   public void testNiceNPEQueryParam() throws SecurityException, NoSuchMethodException, IOException {
+      Method method = TestQuery.class.getMethod("foo3", String.class);
+      try {
+         factory(TestPath.class).createRequest(method, (String) null);
+      } catch (NullPointerException e) {
+         assertEquals(e.getMessage(), "param{robbie} for method TestQuery.foo3");
+      }
+   }
+
+   public void testNoNPEOnQueryParamWithNullable() throws SecurityException, NoSuchMethodException {
+      Method method = TestQuery.class.getMethod("foo3Nullable", String.class);
+      HttpRequest request = factory(TestPath.class).createRequest(method, (String) null);
+      assertEquals(request.getEndpoint().getHost(), "localhost");
+      assertEquals(request.getEndpoint().getPath(), "/");
+      assertEquals(request.getEndpoint().getQuery(), "foo=bar&fooble=baz");
+      assertEquals(request.getMethod(), "FOO");
+   }
 
    public interface TestPayloadParamVarargs {
       @POST
@@ -578,7 +603,7 @@
       assertNonPayloadHeadersEqual(request, "");
       assertPayloadEquals(request, "foo", "application/octet-stream", false);
    }
-
+   
    public void testHttpRequestWithOnlyContentType() throws SecurityException, NoSuchMethodException, IOException {
       Method method = TestPayloadParamVarargs.class.getMethod("post", HttpRequestOptions.class);
       HttpRequest request = factory(TestPayloadParamVarargs.class).createRequest(method, new TestHttpRequestOptions().payload("fooya"));
@@ -1397,6 +1422,11 @@
       @Path("/{path}")
       public void onePath(@PathParam("path") String path) {
       }
+      
+      @GET
+      @Path("/{path}")
+      public void onePathNullable(@Nullable @PathParam("path") String path) {
+      }
 
       @GET
       @Path("/{path1}/{path2}")
@@ -1435,7 +1465,17 @@
       public void onePathParamExtractorMethod(String path) {
       }
    }
-
+   
+   @Test
+   public void testNiceNPEPathParam() throws SecurityException, NoSuchMethodException, IOException {
+      Method method = TestPath.class.getMethod("onePath", String.class);
+      try {
+         factory(TestPath.class).createRequest(method, (String) null);
+      } catch (NullPointerException e) {
+         assertEquals(e.getMessage(), "param{path} for method TestPath.onePath");
+      }
+   }
+   
    @Test
    public void testPathParamExtractor() throws SecurityException, NoSuchMethodException, IOException {
       Method method = TestPath.class.getMethod("onePathParamExtractor", String.class);
@@ -1462,7 +1502,17 @@
       assertNonPayloadHeadersEqual(request, "");
       assertPayloadEquals(request, null, null, false);
    }
-
+   
+   @Test
+   public void testNiceNPEMatrixParam() throws SecurityException, NoSuchMethodException, IOException {
+      Method method = TestPath.class.getMethod("oneMatrixParamExtractor", String.class);
+      try {
+         factory(TestPath.class).createRequest(method, (String) null);
+      } catch (NullPointerException e) {
+         assertEquals(e.getMessage(), "param{one} for method TestPath.oneMatrixParamExtractor");
+      }
+   }
+   
    @Test
    public void testFormParamExtractor() throws SecurityException, NoSuchMethodException, IOException {
       Method method = TestPath.class.getMethod("oneFormParamExtractor", String.class);
@@ -1471,7 +1521,17 @@
       assertNonPayloadHeadersEqual(request, "");
       assertPayloadEquals(request, "one=l", "application/x-www-form-urlencoded", false);
    }
-
+   
+   @Test
+   public void testNiceNPEFormParam() throws SecurityException, NoSuchMethodException, IOException {
+      Method method = TestPath.class.getMethod("oneFormParamExtractor", String.class);
+      try {
+         factory(TestPath.class).createRequest(method, (String) null);
+      } catch (NullPointerException e) {
+         assertEquals(e.getMessage(), "param{one} for method TestPath.oneFormParamExtractor");
+      }
+   }
+   
    @Test
    public void testParamExtractorMethod() throws SecurityException, NoSuchMethodException {
       Method method = TestPath.class.getMethod("onePathParamExtractorMethod", String.class);
diff --git a/labs/abiquo/NOTICE b/labs/abiquo/NOTICE
new file mode 100644
index 0000000..bf10c41
--- /dev/null
+++ b/labs/abiquo/NOTICE
@@ -0,0 +1,29 @@
+====
+    Licensed to jclouds, Inc. (jclouds) under one or more
+    contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  jclouds licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+====
+
+jclouds
+Copyright 2009-2011 jclouds, Inc.
+
+This product includes software developed at
+Abiquo Holdings S.L. (http://www.abiquo.com/).
+
+The following Abiquo dependencies are distributed under
+the GNU Lesser General Public License version 3:
+  com.abiquo:api-model-transport
+  com.abiquo:am-model
diff --git a/labs/abiquo/README.md b/labs/abiquo/README.md
new file mode 100644
index 0000000..bb545d5
--- /dev/null
+++ b/labs/abiquo/README.md
@@ -0,0 +1,21 @@
+Jclouds Abiquo Provider
+=======================
+
+This is the jclouds Abiquo provider. It enables compute features for the Abiquo cloud platform.
+
+Documentation
+-------------
+
+Detailed information about the Abiquo REST API can be found in the
+[Abiquo documentation page](http://community.abiquo.com).
+
+All information about building and using the **jclouds-abiquo** provider in your own project
+can be found in the [Project Wiki](https://github.com/abiquo/jclouds-abiquo/wiki).
+
+
+Issue Tracking
+--------------
+
+If you find any issue in the provider api, please submit it to the [Bug tracking system](http://jira.abiquo.com/browse/ABIQUOJC)
+and we will do our best to fix it.
+
diff --git a/labs/abiquo/pom.xml b/labs/abiquo/pom.xml
new file mode 100644
index 0000000..9eab759
--- /dev/null
+++ b/labs/abiquo/pom.xml
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.jclouds</groupId>
+        <artifactId>jclouds-project</artifactId>
+        <version>1.5.0-SNAPSHOT</version>
+        <relativePath>../../project/pom.xml</relativePath>
+    </parent>
+    
+    <groupId>org.jclouds.labs</groupId>
+    <artifactId>abiquo</artifactId>
+    <name>jclouds Abiquo api</name>
+    <description>jclouds components to access an implementation of Abiquo</description>
+    <packaging>bundle</packaging>
+    
+    <properties>
+        <abiquo.version>2.1-SNAPSHOT</abiquo.version>
+        <test.abiquo.endpoint>http://localhost/api</test.abiquo.endpoint>
+        <test.abiquo.identity>FIXME</test.abiquo.identity>
+        <test.abiquo.credential>FIXME</test.abiquo.credential>
+        <test.abiquo.api-version></test.abiquo.api-version>
+        <test.abiquo.build-version></test.abiquo.build-version>
+        <jclouds.osgi.export>org.jclouds.abiquo*;version="${project.version}"</jclouds.osgi.export>
+        <jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
+    </properties>
+    
+    <!-- To be removed when the Abiquo deps are in Maven Central -->
+    <repositories>
+        <repository>
+            <id>abiquo-repo</id>
+            <name>Abiquo Maven Repository</name>
+            <url>http://repo.community.abiquo.com/repo</url>
+        </repository>
+    </repositories>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds</groupId>
+            <artifactId>jclouds-compute</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!-- Abiquo -->
+        <dependency>
+            <groupId>com.abiquo</groupId>
+            <artifactId>api-model-transport</artifactId>
+            <version>${abiquo.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>javax.ws.rs</groupId>
+                    <artifactId>jsr311-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.uncommons</groupId>
+                    <artifactId>reportng</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.abiquo</groupId>
+            <artifactId>am-model</artifactId>
+            <version>${abiquo.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>javax.ws.rs</groupId>
+                    <artifactId>jsr311-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.uncommons</groupId>
+                    <artifactId>reportng</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- Required for class SyndLink (imported form RESTLink) : TODO remove this dependency -->
+        <dependency>
+            <groupId>org.apache.wink</groupId>
+            <artifactId>wink-common</artifactId>
+            <version>1.1-incubating</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-jdk14</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>javax.ws.rs</groupId>
+                    <artifactId>jsr311-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>javax.xml.stream</groupId>
+                    <artifactId>stax-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds</groupId>
+            <artifactId>jclouds-compute</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds.driver</groupId>
+            <artifactId>jclouds-sshj</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds.driver</groupId>
+            <artifactId>jclouds-slf4j</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <version>1.0.0</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.0.0</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    
+    <build>
+        <testResources>
+            <testResource>
+                <directory>src/test/resources</directory>
+                <filtering>true</filtering>
+            </testResource>
+        </testResources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>**/*IntegrationTest.java</exclude>
+                        <exclude>**/*LiveTest.java</exclude>
+                        <exclude>**/*LiveApiTest.java</exclude>
+                        <exclude>**/*LiveUcsTest.java</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <profiles>
+        <profile>
+            <id>live</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        <test.abiquo.identity>${test.abiquo.idenfity}</test.abiquo.identity>
+                                        <test.abiquo.credential>${test.abiquo.credential}</test.abiquo.credential>
+                                        <test.abiquo.api-version>${test.abiquo.api-version}</test.abiquo.api-version>
+                                        <test.abiquo.build-version>${test.abiquo.build-version}</test.abiquo.build-version>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>api</id>
+            <build>
+                <filters>
+                    <filter>src/test/resources/filters/filters.properties</filter>
+                </filters>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <!-- Infrastructure tests must not be executed in parallel.
+                                         They modify concurrently the same infrastructure resources. -->
+                                    <threadCount>1</threadCount>
+                                    <excludes>
+                                        <exclude>none</exclude>
+                                    </excludes>
+                                    <includes>
+                                        <include>**/*LiveApiTest.java</include>
+                                    </includes>
+                                    <systemPropertyVariables>
+                                        <test.abiquo.identity>${test.abiquo.identity}</test.abiquo.identity>
+                                        <test.abiquo.credential>${test.abiquo.credential}</test.abiquo.credential>
+                                        <test.abiquo.api-version>${test.abiquo.api-version}</test.abiquo.api-version>
+                                        <test.abiquo.build-version>${test.abiquo.build-version}</test.abiquo.build-version>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>jenkins</id>
+            <build>
+                <filters>
+                    <filter>src/test/resources/filters/filters_jenkins.properties</filter>
+                </filters>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <threadCount>1</threadCount>
+                                    <excludes>
+                                        <exclude>none</exclude>
+                                    </excludes>
+                                    <includes>
+                                        <include>**/*Live*.java</include>
+                                    </includes>
+                                    <systemPropertyVariables>
+                                        <test.abiquo.identity>${test.abiquo.idenfity}</test.abiquo.identity>
+                                        <test.abiquo.credential>${test.abiquo.credential}</test.abiquo.credential>
+                                        <test.abiquo.api-version>${test.abiquo.api-version}</test.abiquo.api-version>
+                                        <test.abiquo.build-version>${test.abiquo.build-version}</test.abiquo.build-version>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <!-- 
+        <profile>
+            <id>ucs</id>
+            <build>
+                <filters>
+                    <filter>src/test/resources/filters/filters.properties</filter>
+                </filters>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <threadCount>1</threadCount>
+                                    <excludes>
+                                        <exclude>none</exclude>
+                                    </excludes>
+                                    <includes>
+                                        <include>**/*LiveApiTest.java</include>
+                                        <include>**/*LiveUcsTest.java</include>
+                                    </includes>
+                                    <systemPropertyVariables>
+                                        <test.abiquo.identity>${test.abiquo.idenfity}</test.abiquo.identity>
+                                        <test.abiquo.credential>${test.abiquo.credential}</test.abiquo.credential>
+                                        <test.abiquo.api-version>${test.abiquo.api-version}</test.abiquo.api-version>
+                                        <test.abiquo.build-version>${test.abiquo.build-version}</test.abiquo.build-version>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        -->
+    </profiles>
+</project>
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoApi.java
new file mode 100644
index 0000000..356274f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoApi.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.features.AdminApi;
+import org.jclouds.abiquo.features.CloudApi;
+import org.jclouds.abiquo.features.ConfigApi;
+import org.jclouds.abiquo.features.EnterpriseApi;
+import org.jclouds.abiquo.features.EventApi;
+import org.jclouds.abiquo.features.InfrastructureApi;
+import org.jclouds.abiquo.features.PricingApi;
+import org.jclouds.abiquo.features.TaskApi;
+import org.jclouds.abiquo.features.VirtualMachineTemplateApi;
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.rest.annotations.Delegate;
+
+/**
+ * Provides synchronous access to Abiquo.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see AbiquoAsyncApi
+ * @author Ignasi Barrera
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface AbiquoApi
+{
+    /**
+     * Provides synchronous access to Admin features.
+     */
+    @Delegate
+    AdminApi getAdminApi();
+
+    /**
+     * Provides synchronous access to Infrastructure features.
+     */
+    @Delegate
+    InfrastructureApi getInfrastructureApi();
+
+    /**
+     * Provides synchronous access to Cloud features.
+     */
+    @Delegate
+    CloudApi getCloudApi();
+
+    /**
+     * Provides synchronous access to Apps library features.
+     */
+    @Delegate
+    VirtualMachineTemplateApi getVirtualMachineTemplateApi();
+
+    /**
+     * Provides synchronous access to Enterprise features.
+     */
+    @Delegate
+    EnterpriseApi getEnterpriseApi();
+
+    /**
+     * Provides synchronous access to configuration features.
+     */
+    @Delegate
+    ConfigApi getConfigApi();
+
+    /**
+     * Provides synchronous access to task asynchronous features.
+     */
+    @Delegate
+    TaskApi getTaskApi();
+
+    /**
+     * Provides synchronous access to Event features.
+     */
+    @Delegate
+    EventApi getEventApi();
+
+    /**
+     * Provides synchronous access to Pricing features.
+     */
+    @Delegate
+    PricingApi getPricingApi();
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoApiMetadata.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoApiMetadata.java
new file mode 100644
index 0000000..78fd985
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoApiMetadata.java
@@ -0,0 +1,124 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo;
+
+import static org.jclouds.Constants.PROPERTY_MAX_REDIRECTS;
+import static org.jclouds.abiquo.config.AbiquoProperties.ASYNC_TASK_MONITOR_DELAY;
+import static org.jclouds.abiquo.config.AbiquoProperties.CREDENTIAL_IS_TOKEN;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.abiquo.compute.config.AbiquoComputeServiceContextModule;
+import org.jclouds.abiquo.config.AbiquoRestClientModule;
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.concurrent.config.ScheduledExecutorServiceModule;
+import org.jclouds.rest.RestContext;
+import org.jclouds.rest.internal.BaseRestApiMetadata;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for Abiquo API.
+ * 
+ * @author Ignasi Barrera
+ */
+public class AbiquoApiMetadata extends BaseRestApiMetadata
+{
+    /** Serial UID. */
+    private static final long serialVersionUID = -8355533493674898171L;
+
+    /** The token describing the rest api context. */
+    public static final TypeToken<RestContext<AbiquoApi, AbiquoAsyncApi>> CONTEXT_TOKEN =
+        new TypeToken<RestContext<AbiquoApi, AbiquoAsyncApi>>()
+        {
+            private static final long serialVersionUID = -5070937833892503232L;
+        };
+
+    public AbiquoApiMetadata()
+    {
+        this(new Builder());
+    }
+
+    protected AbiquoApiMetadata(final Builder builder)
+    {
+        super(builder);
+    }
+
+    public static Properties defaultProperties()
+    {
+        Properties properties = BaseRestApiMetadata.defaultProperties();
+        // By default redirects will be handled in the domain objects
+        properties.setProperty(PROPERTY_MAX_REDIRECTS, "0");
+        // The default polling delay between AsyncTask monitor requests
+        properties.setProperty(ASYNC_TASK_MONITOR_DELAY, "5000");
+        // By default the provided credential is not a token
+        properties.setProperty(CREDENTIAL_IS_TOKEN, "false");
+        return properties;
+    }
+
+    @Override
+    public Builder toBuilder()
+    {
+        return new Builder().fromApiMetadata(this);
+    }
+
+    public static class Builder extends BaseRestApiMetadata.Builder
+    {
+        private static final String DOCUMENTATION_ROOT = "http://community.abiquo.com/display/ABI"
+            + CharMatcher.DIGIT.retainFrom(AbiquoAsyncApi.API_VERSION);
+
+        protected Builder()
+        {
+            super(AbiquoApi.class, AbiquoAsyncApi.class);
+            id("abiquo")
+                .name("Abiquo API")
+                .identityName("API Username")
+                .credentialName("API Password")
+                .documentation(URI.create(DOCUMENTATION_ROOT + "/API+Reference"))
+                .defaultEndpoint("http://localhost/api")
+                .version(AbiquoAsyncApi.API_VERSION)
+                .buildVersion(AbiquoAsyncApi.BUILD_VERSION)
+                .view(TypeToken.of(AbiquoContext.class))
+                .defaultProperties(AbiquoApiMetadata.defaultProperties())
+                .defaultModules(
+                    ImmutableSet.<Class< ? extends Module>> of(AbiquoRestClientModule.class,
+                        AbiquoComputeServiceContextModule.class,
+                        ScheduledExecutorServiceModule.class));
+        }
+
+        @Override
+        public AbiquoApiMetadata build()
+        {
+            return new AbiquoApiMetadata(this);
+        }
+
+        @Override
+        public Builder fromApiMetadata(final ApiMetadata in)
+        {
+            super.fromApiMetadata(in);
+            return this;
+        }
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoAsyncApi.java
new file mode 100644
index 0000000..c46e7a0
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoAsyncApi.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo;
+
+import org.jclouds.abiquo.features.AdminAsyncApi;
+import org.jclouds.abiquo.features.CloudAsyncApi;
+import org.jclouds.abiquo.features.ConfigAsyncApi;
+import org.jclouds.abiquo.features.EnterpriseAsyncApi;
+import org.jclouds.abiquo.features.EventAsyncApi;
+import org.jclouds.abiquo.features.InfrastructureAsyncApi;
+import org.jclouds.abiquo.features.PricingAsyncApi;
+import org.jclouds.abiquo.features.TaskAsyncApi;
+import org.jclouds.abiquo.features.VirtualMachineTemplateAsyncApi;
+import org.jclouds.rest.annotations.Delegate;
+
+import com.abiquo.model.transport.SingleResourceTransportDto;
+
+/**
+ * Provides asynchronous access to Abiquo via their REST API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see InfrastructureAsyncApi
+ * @author Ignasi Barrera
+ */
+public interface AbiquoAsyncApi
+{
+    /**
+     * The version of the supported Abiquo API.
+     */
+    public static final String API_VERSION = SingleResourceTransportDto.API_VERSION;
+
+    /**
+     * The supported build version of the Abiquo Api.
+     */
+    public static final String BUILD_VERSION = "7bbfe95-158721b";
+
+    /**
+     * Provides asynchronous access to Admin features.
+     */
+    @Delegate
+    AdminAsyncApi getAdminApi();
+
+    /**
+     * Provides asynchronous access to Infrastructure features.
+     */
+    @Delegate
+    InfrastructureAsyncApi getInfrastructureApi();
+
+    /**
+     * Provides asynchronous access to Cloud features.
+     */
+    @Delegate
+    CloudAsyncApi getCloudApi();
+
+    /**
+     * Provides asynchronous access to Apps library features.
+     */
+    @Delegate
+    VirtualMachineTemplateAsyncApi getVirtualMachineTemplateApi();
+
+    /**
+     * Provides asynchronous access to Enterprise features.
+     */
+    @Delegate
+    EnterpriseAsyncApi getEnterpriseApi();
+
+    /**
+     * Provides asynchronous access to configuration features.
+     */
+    @Delegate
+    ConfigAsyncApi getConfigApi();
+
+    /**
+     * Provides asynchronous access to task asynchronous features.
+     */
+    @Delegate
+    TaskAsyncApi getTaskApi();
+
+    /**
+     * Provides asynchronous access to Event features.
+     */
+    @Delegate
+    EventAsyncApi getEventApi();
+
+    /**
+     * Provides asynchronous access to Pricing features.
+     */
+    @Delegate
+    PricingAsyncApi getPricingApi();
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoContext.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoContext.java
new file mode 100644
index 0000000..a390a78
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/AbiquoContext.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo;
+
+import org.jclouds.abiquo.features.services.AdministrationService;
+import org.jclouds.abiquo.features.services.CloudService;
+import org.jclouds.abiquo.features.services.EventService;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.features.services.PricingService;
+import org.jclouds.abiquo.features.services.SearchService;
+import org.jclouds.abiquo.internal.AbiquoContextImpl;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.rest.RestContext;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * Abiquo {@link ComputeServiceContext} implementation to expose high level Abiquo functionalities.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(AbiquoContextImpl.class)
+public interface AbiquoContext extends ComputeServiceContext
+{
+    /**
+     * Returns the Abiquo API context, providing direct access to the Abiquo Rest API.
+     * 
+     * @return The Abiquo API context.
+     */
+    RestContext<AbiquoApi, AbiquoAsyncApi> getApiContext();
+
+    /**
+     * Returns the administration service.
+     * <p>
+     * This service provides an entry point to infrastructure administration tasks.
+     */
+    AdministrationService getAdministrationService();
+
+    /**
+     * Returns the cloud service.
+     * <p>
+     * This service provides an entry point to cloud management tasks.
+     */
+    CloudService getCloudService();
+
+    /**
+     * Returns the search service.
+     * <p>
+     * This service provides an entry point to listing and filtering tasks.
+     */
+    SearchService getSearchService();
+
+    /**
+     * Returns the monitoring service.
+     * <p>
+     * This service provides an entry point to asynchronous task monitoring tasks.
+     */
+    MonitoringService getMonitoringService();
+
+    /**
+     * Returns the event service.
+     * <p>
+     * This service provides an entry point to event management tasks.
+     */
+    EventService getEventService();
+
+    /**
+     * Returns the pricing service.
+     * <p>
+     * This service provides an entry point to pricing management tasks.
+     */
+    PricingService getPricingService();
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/AppendToPath.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/AppendToPath.java
new file mode 100644
index 0000000..06ea947
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/AppendToPath.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+/**
+ * Appends the parameter value to the end of the request URI.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AppendToPath implements Binder
+{
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        // Append the parameter to the request URI
+        String valueToAppend = getValue(request, checkNotNull(input, "input"));
+        URI path = URI.create(request.getEndpoint().toString() + "/" + valueToAppend);
+        return (R) request.toBuilder().endpoint(path).build();
+    }
+
+    /**
+     * Get the value that will be appended to the request URI.
+     */
+    protected <R extends HttpRequest> String getValue(final R request, final Object input)
+    {
+        return input.toString();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindLinkToPath.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindLinkToPath.java
new file mode 100644
index 0000000..f432d58
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindLinkToPath.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy 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.abiquo.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+import com.abiquo.model.rest.RESTLink;
+
+/**
+ * Binds the given link to the uri.
+ * 
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class BindLinkToPath extends BindToPath
+{
+
+    @Override
+    protected String getNewEndpoint(final GeneratedHttpRequest gRequest, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof RESTLink,
+            "this binder is only valid for RESTLink objects");
+
+        return ((RESTLink) input).getHref();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindLinkToPathAndAcceptHeader.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindLinkToPathAndAcceptHeader.java
new file mode 100644
index 0000000..6479403
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindLinkToPathAndAcceptHeader.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+import javax.ws.rs.core.HttpHeaders;
+
+import org.jclouds.http.HttpRequest;
+
+import com.abiquo.model.rest.RESTLink;
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Binds the given link to the uri and the Accept header.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindLinkToPathAndAcceptHeader extends BindLinkToPath
+{
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        R updatedRequest = super.bindToRequest(request, input);
+        return addHeader(updatedRequest, HttpHeaders.ACCEPT, ((RESTLink) input).getType());
+    }
+
+    @SuppressWarnings("unchecked")
+    @VisibleForTesting
+    <R extends HttpRequest> R addHeader(final R request, final String header, final String value)
+    {
+        return (R) request.toBuilder()
+            .replaceHeader(HttpHeaders.ACCEPT, checkNotNull(value, "value")).build();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindRefsToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindRefsToPayload.java
new file mode 100644
index 0000000..6a782e7
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindRefsToPayload.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.model.transport.SingleResourceTransportDto;
+
+/**
+ * Bind multiple objects to the payload of the request as a list of links.
+ * 
+ * @author Ignasi Barrera
+ */
+public abstract class BindRefsToPayload extends BindToXMLPayload
+{
+    @Inject
+    public BindRefsToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    protected abstract String getRelToUse(final Object input);
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof SingleResourceTransportDto[],
+            "this binder is only valid for SingleResourceTransportDto arrays");
+
+        SingleResourceTransportDto[] dtos = (SingleResourceTransportDto[]) input;
+        LinksDto refs = new LinksDto();
+
+        for (SingleResourceTransportDto dto : dtos)
+        {
+            RESTLink editLink = checkNotNull(dto.getEditLink(), "entity must have an edit link");
+
+            // Do not add repeated references
+            if (refs.searchLinkByHref(editLink.getHref()) == null)
+            {
+                refs.addLink(new RESTLink(getRelToUse(input), editLink.getHref()));
+            }
+        }
+
+        return super.bindToRequest(request, refs);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindToPath.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindToPath.java
new file mode 100644
index 0000000..2b27329
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindToPath.java
@@ -0,0 +1,159 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.lang.annotation.Annotation;
+import java.net.URI;
+import java.util.Arrays;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+import org.jclouds.rest.binders.BindException;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+/**
+ * Binds the given object to the path..
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindToPath implements Binder
+{
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
+            "this binder is only valid for GeneratedHttpRequests");
+        GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
+        checkState(gRequest.getArgs() != null, "args should be initialized at this point");
+
+        // Update the request URI with the configured link URI
+        String newEndpoint = getNewEndpoint(gRequest, input);
+        return bindToPath(request, newEndpoint);
+    }
+
+    /**
+     * Get the new endpoint to use.
+     * 
+     * @param gRequest The request.
+     * @param input The input parameter.
+     * @return The new endpoint to use.
+     */
+    protected String getNewEndpoint(final GeneratedHttpRequest gRequest, final Object input)
+    {
+        SingleResourceTransportDto dto = checkValidInput(input);
+        return getLinkToUse(gRequest, dto).getHref();
+    }
+
+    /**
+     * Get the link to be used to build the request URI.
+     * 
+     * @param request The current request.
+     * @param payload The object containing the link.
+     * @return The link to be used to build the request URI.
+     */
+    static RESTLink getLinkToUse(final GeneratedHttpRequest request,
+        final SingleResourceTransportDto payload)
+    {
+        int argIndex = request.getArgs().indexOf(payload);
+        Annotation[] annotations = request.getJavaMethod().getParameterAnnotations()[argIndex];
+
+        EndpointLink linkName =
+            (EndpointLink) Iterables.find(Arrays.asList(annotations),
+                Predicates.instanceOf(EndpointLink.class), null);
+
+        if (linkName == null)
+        {
+            throw new BindException(request,
+                "Expected a EndpointLink annotation but not found in the parameter");
+        }
+
+        return checkNotNull(payload.searchLink(linkName.value()),
+            "No link was found in object with rel: " + linkName);
+    }
+
+    /**
+     * Bind the given link to the request URI.
+     * 
+     * @param request The request to modify.
+     * @param endpoint The endpoint to use as the request URI.
+     * @return The updated request.
+     */
+    @SuppressWarnings("unchecked")
+    static <R extends HttpRequest> R bindToPath(final R request, final String endpoint)
+    {
+        // Preserve current query and matrix parameters
+        String newEndpoint = endpoint + getParameterString(request);
+
+        // Replace the URI with the edit link in the DTO
+        URI path = URI.create(newEndpoint);
+        return (R) request.toBuilder().endpoint(path).build();
+    }
+
+    protected static SingleResourceTransportDto checkValidInput(final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof SingleResourceTransportDto,
+            "this binder is only valid for SingleResourceTransportDto objects");
+
+        return (SingleResourceTransportDto) input;
+    }
+
+    protected static <R extends HttpRequest> String getParameterString(final R request)
+    {
+        String endpoint = request.getEndpoint().toString();
+
+        int query = endpoint.indexOf('?');
+        int matrix = endpoint.indexOf(';');
+
+        if (query == -1 && matrix == -1)
+        {
+            // No parameters
+            return "";
+        }
+        else if (query != -1 && matrix != -1)
+        {
+            // Both parameter types
+            return endpoint.substring(query < matrix ? query : matrix);
+        }
+        else if (query != -1)
+        {
+            // Only request parameters
+            return endpoint.substring(query);
+        }
+        else
+        {
+            // Only matrix parameters
+            return endpoint.substring(matrix);
+        }
+
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindToXMLPayloadAndPath.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindToXMLPayloadAndPath.java
new file mode 100644
index 0000000..8e133d9
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/BindToXMLPayloadAndPath.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.PUT;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.transport.SingleResourceTransportDto;
+
+/**
+ * Binds teh given object to the payload and extracts the path parameters from the edit link.
+ * <p>
+ * This method should be used in {@link PUT} methods to automatically extract the path parameters
+ * from the edit link of the updated object.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindToXMLPayloadAndPath extends BindToXMLPayload
+{
+    @Inject
+    public BindToXMLPayloadAndPath(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object payload)
+    {
+        checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
+            "this binder is only valid for GeneratedHttpRequests");
+        GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
+        checkState(gRequest.getArgs() != null, "args should be initialized at this point");
+
+        // Update the request URI with the configured link URI
+        String newEndpoint = getNewEndpoint(gRequest, payload);
+        R updatedRequest = BindToPath.bindToPath(request, newEndpoint);
+
+        // Add the payload
+        return super.bindToRequest(updatedRequest, payload);
+    }
+
+    /**
+     * Get the new endpoint to use.
+     * 
+     * @param gRequest The request.
+     * @param input The input parameter.
+     * @return The new endpoint to use.
+     */
+    protected String getNewEndpoint(final GeneratedHttpRequest gRequest, final Object input)
+    {
+        SingleResourceTransportDto dto = BindToPath.checkValidInput(input);
+        return BindToPath.getLinkToUse(gRequest, dto).getHref();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindHardDiskRefsToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindHardDiskRefsToPayload.java
new file mode 100644
index 0000000..f8595ec
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindHardDiskRefsToPayload.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.binders.BindRefsToPayload;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+
+/**
+ * Bind multiple {@link DiskManagementDto} objects to the payload of the request as a list of links.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindHardDiskRefsToPayload extends BindRefsToPayload
+{
+    @Inject
+    public BindHardDiskRefsToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    protected String getRelToUse(final Object input)
+    {
+        return "disk";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindIpRefToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindIpRefToPayload.java
new file mode 100644
index 0000000..1ac67b6
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindIpRefToPayload.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.AbstractIpDto;
+
+/**
+ * Bind the link reference to an {@link AbstractIpDto} object into the payload.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindIpRefToPayload extends BindToXMLPayload
+{
+    @Inject
+    public BindIpRefToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof AbstractIpDto,
+            "this binder is only valid for AbstractIpDto objects");
+
+        AbstractIpDto ip = (AbstractIpDto) input;
+        RESTLink selfLink =
+            checkNotNull(ip.searchLink("self"), "AbstractIpDto must have an self link");
+
+        LinksDto refs = new LinksDto();
+        refs.addLink(new RESTLink(selfLink.getTitle(), selfLink.getHref()));
+
+        return super.bindToRequest(request, refs);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindIpRefsToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindIpRefsToPayload.java
new file mode 100644
index 0000000..8ee5b58
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindIpRefsToPayload.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.util.LinkUtils;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.AbstractIpDto;
+
+/**
+ * Bind the link reference to an {@link AbstractIpDto} object into the payload.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindIpRefsToPayload extends BindToXMLPayload
+{
+    @Inject
+    public BindIpRefsToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof AbstractIpDto[],
+            "this binder is only valid for AbstractIpDto arrays");
+
+        AbstractIpDto[] ips = (AbstractIpDto[]) input;
+        LinksDto refs = new LinksDto();
+
+        for (AbstractIpDto ip : ips)
+        {
+            RESTLink selfLink =
+                checkNotNull(LinkUtils.getSelfLink(ip),
+                    "AbstractIpDto must have an edit or self link");
+            if (refs.searchLinkByHref(selfLink.getHref()) == null)
+            {
+                RESTLink ref = new RESTLink(selfLink.getTitle(), selfLink.getHref());
+                ref.setType(selfLink.getType());
+                refs.addLink(ref);
+            }
+        }
+
+        return super.bindToRequest(request, refs);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindMoveVolumeToPath.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindMoveVolumeToPath.java
new file mode 100644
index 0000000..b99efce
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindMoveVolumeToPath.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+
+/**
+ * Binds the move volume action to the request endpoint.
+ * 
+ * @author Ignasi Barrera
+ */
+public class BindMoveVolumeToPath extends BindToPath
+{
+
+    @Override
+    protected String getNewEndpoint(final GeneratedHttpRequest gRequest, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof VolumeManagementDto,
+            "this binder is only valid for VolumeManagementDto objects");
+
+        VolumeManagementDto volume = (VolumeManagementDto) input;
+        RESTLink editLink =
+            checkNotNull(volume.getEditLink(), "VolumeManagementDto must have an edit link");
+
+        return editLink.getHref() + "/action/move";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindNetworkConfigurationRefToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindNetworkConfigurationRefToPayload.java
new file mode 100644
index 0000000..6b8ca7f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindNetworkConfigurationRefToPayload.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.cloud.VirtualMachineDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+/**
+ * Bind multiple objects to the payload of the request as a list of links.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindNetworkConfigurationRefToPayload extends BindToXMLPayload
+{
+    @Inject
+    public BindNetworkConfigurationRefToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest,
+            "this binder is only valid for GeneratedHttpRequests");
+        checkArgument(checkNotNull(input, "input") instanceof VLANNetworkDto,
+            "this binder is only valid for VLANNetworkDto");
+        GeneratedHttpRequest gRequest = (GeneratedHttpRequest) request;
+        checkState(gRequest.getArgs() != null, "args should be initialized at this point");
+
+        VLANNetworkDto network = (VLANNetworkDto) input;
+        VirtualMachineDto vm =
+            (VirtualMachineDto) Iterables.find(gRequest.getArgs(),
+                Predicates.instanceOf(VirtualMachineDto.class));
+
+        RESTLink configLink =
+            checkNotNull(vm.searchLink("configurations"), "missing required link");
+
+        LinksDto dto = new LinksDto();
+        dto.addLink(new RESTLink("network_configuration", configLink.getHref() + "/"
+            + network.getId()));
+
+        return super.bindToRequest(request, dto);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindNetworkRefToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindNetworkRefToPayload.java
new file mode 100644
index 0000000..261af82
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindNetworkRefToPayload.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+
+/**
+ * Bind the link reference to an {@link VLANNetworkDto} object into the payload.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindNetworkRefToPayload extends BindToXMLPayload
+{
+    @Inject
+    public BindNetworkRefToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof VLANNetworkDto,
+            "this binder is only valid for VLANNetworkDto objects");
+
+        VLANNetworkDto network = (VLANNetworkDto) input;
+        RESTLink editLink =
+            checkNotNull(network.getEditLink(), "VLANNetworkDto must have an edit link");
+
+        LinksDto refs = new LinksDto();
+        switch (network.getType())
+        {
+            case INTERNAL:
+                refs.addLink(new RESTLink("internalnetwork", editLink.getHref()));
+                break;
+            case EXTERNAL:
+                refs.addLink(new RESTLink("externalnetwork", editLink.getHref()));
+                break;
+            case PUBLIC:
+                refs.addLink(new RESTLink("publicnetwork", editLink.getHref()));
+                break;
+            case UNMANAGED:
+                refs.addLink(new RESTLink("unmanagednetwork", editLink.getHref()));
+                break;
+            default:
+                // TODO: EXTERNAL_UNMANAGED network type
+                throw new IllegalArgumentException("Unsupported network type");
+        }
+
+        return super.bindToRequest(request, refs);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindUnmanagedIpRefToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindUnmanagedIpRefToPayload.java
new file mode 100644
index 0000000..cef4c84
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindUnmanagedIpRefToPayload.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.AbstractIpDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+
+/**
+ * Bind the link reference to an {@link AbstractIpDto} object into the payload.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindUnmanagedIpRefToPayload extends BindToXMLPayload
+{
+    @Inject
+    public BindUnmanagedIpRefToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof VLANNetworkDto,
+            "this binder is only valid for VLANNetworkDto objects");
+
+        VLANNetworkDto network = (VLANNetworkDto) input;
+        checkArgument(network.getType() == NetworkType.UNMANAGED,
+            "this binder is only valid for UNMANAGED networks");
+
+        RESTLink ipsLink =
+            checkNotNull(network.searchLink("ips"), "VLANNetworkDto must have an ips link");
+
+        LinksDto refs = new LinksDto();
+        refs.addLink(new RESTLink("unmanagedip", ipsLink.getHref()));
+
+        return super.bindToRequest(request, refs);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindVirtualDatacenterRefToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindVirtualDatacenterRefToPayload.java
new file mode 100644
index 0000000..c6cb64b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindVirtualDatacenterRefToPayload.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+
+/**
+ * Bind multiple {@link VolumeManagementDto} objects to the payload of the request as a list of
+ * links.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindVirtualDatacenterRefToPayload extends BindToXMLPayload
+{
+    @Inject
+    public BindVirtualDatacenterRefToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof VirtualDatacenterDto,
+            "this binder is only valid for VirtualDatacenterDto objects");
+
+        VirtualDatacenterDto vdc = (VirtualDatacenterDto) input;
+        RESTLink editLink =
+            checkNotNull(vdc.getEditLink(), "VirtualDatacenterDto must have an edit link");
+        LinksDto refs = new LinksDto();
+        refs.addLink(new RESTLink("virtualdatacenter", editLink.getHref()));
+
+        return super.bindToRequest(request, refs);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindVolumeRefsToPayload.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindVolumeRefsToPayload.java
new file mode 100644
index 0000000..d71b3c7
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/cloud/BindVolumeRefsToPayload.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.binders.BindRefsToPayload;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+
+/**
+ * Bind multiple {@link VolumeManagementDto} objects to the payload of the request as a list of
+ * links.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindVolumeRefsToPayload extends BindRefsToPayload
+{
+    @Inject
+    public BindVolumeRefsToPayload(final XMLParser xmlParser)
+    {
+        super(xmlParser);
+    }
+
+    @Override
+    protected String getRelToUse(final Object input)
+    {
+        return "volume";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/AppendMachineIdToPath.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/AppendMachineIdToPath.java
new file mode 100644
index 0000000..56d7960
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/AppendMachineIdToPath.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.binders.AppendToPath;
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+import org.jclouds.abiquo.functions.infrastructure.ParseMachineId;
+import org.jclouds.http.HttpRequest;
+
+/**
+ * Append the {@link Machine} id to the request URI.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AppendMachineIdToPath extends AppendToPath
+{
+    private ParseMachineId parser;
+
+    @Inject
+    public AppendMachineIdToPath(final ParseMachineId parser)
+    {
+        super();
+        this.parser = parser;
+    }
+
+    @Override
+    protected <R extends HttpRequest> String getValue(final R request, final Object input)
+    {
+        return parser.apply(input);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/AppendRemoteServiceTypeToPath.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/AppendRemoteServiceTypeToPath.java
new file mode 100644
index 0000000..4db84be
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/AppendRemoteServiceTypeToPath.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.binders.AppendToPath;
+import org.jclouds.abiquo.functions.infrastructure.ParseRemoteServiceType;
+import org.jclouds.http.HttpRequest;
+
+/**
+ * Append the {@link RemoteServiceType} service to the request URI.
+ * <p>
+ * This method assumes that the input object is a {@link RemoteServiceType} enumeration.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AppendRemoteServiceTypeToPath extends AppendToPath
+{
+    private ParseRemoteServiceType parser;
+
+    @Inject
+    public AppendRemoteServiceTypeToPath(final ParseRemoteServiceType parser)
+    {
+        super();
+        this.parser = parser;
+    }
+
+    @Override
+    protected <R extends HttpRequest> String getValue(final R request, final Object input)
+    {
+        return parser.apply(input);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/BindSupportedDevicesLinkToPath.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/BindSupportedDevicesLinkToPath.java
new file mode 100644
index 0000000..6bf6d5f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/BindSupportedDevicesLinkToPath.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+
+/**
+ * Binds the given link to the uri appends the supported devices action path.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindSupportedDevicesLinkToPath extends BindToPath
+{
+
+    @Override
+    protected String getNewEndpoint(final GeneratedHttpRequest gRequest, final Object input)
+    {
+        return super.getNewEndpoint(gRequest, input) + "/action/supported";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindLogicServerParameters.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindLogicServerParameters.java
new file mode 100644
index 0000000..ef2072f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindLogicServerParameters.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure.ucs;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+
+/**
+ * Binds logic server query parameters to request. This method assumes that the input object is a
+ * {@link LogicServerDto}.
+ * 
+ * @author Francesc Montserrat
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindLogicServerParameters implements Binder
+{
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof LogicServerDto,
+            "this binder is only valid for LogicServerDto objects");
+
+        LogicServerDto server = (LogicServerDto) input;
+
+        return (R) request.toBuilder().addQueryParam("lsName", server.getName()).build();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindOrganizationParameters.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindOrganizationParameters.java
new file mode 100644
index 0000000..ddde0cd
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindOrganizationParameters.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure.ucs;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.Binder;
+
+import com.abiquo.server.core.infrastructure.OrganizationDto;
+
+/**
+ * Binds organization query parameters to request. This method assumes that the input object is a
+ * {@link OrganizationDto}.
+ * 
+ * @author Francesc Montserrat
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BindOrganizationParameters implements Binder
+{
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R extends HttpRequest> R bindToRequest(final R request, final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof OrganizationDto,
+            "this binder is only valid for OrganizationDto objects");
+
+        OrganizationDto org = (OrganizationDto) input;
+
+        return (R) request.toBuilder().addQueryParam("org", org.getDn()).build();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/config/AbiquoComputeServiceContextModule.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/config/AbiquoComputeServiceContextModule.java
new file mode 100644
index 0000000..4007b0a
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/config/AbiquoComputeServiceContextModule.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.config;
+
+import org.jclouds.abiquo.compute.functions.DatacenterToLocation;
+import org.jclouds.abiquo.compute.functions.VirtualMachineTemplateToHardware;
+import org.jclouds.abiquo.compute.functions.VirtualMachineTemplateToImage;
+import org.jclouds.abiquo.compute.functions.VirtualMachineToNodeMetadata;
+import org.jclouds.abiquo.compute.options.AbiquoTemplateOptions;
+import org.jclouds.abiquo.compute.strategy.AbiquoComputeServiceAdapter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.domain.Location;
+import org.jclouds.location.suppliers.ImplicitLocationSupplier;
+import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstZone;
+
+import com.google.common.base.Function;
+import com.google.inject.Scopes;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Abiquo Compute service configuration module.
+ * 
+ * @author Ignasi Barrera
+ */
+public class AbiquoComputeServiceContextModule
+    extends
+    ComputeServiceAdapterContextModule<VirtualMachine, VirtualMachineTemplate, VirtualMachineTemplate, Datacenter>
+{
+
+    @Override
+    protected void configure()
+    {
+        super.configure();
+        bind(
+            new TypeLiteral<ComputeServiceAdapter<VirtualMachine, VirtualMachineTemplate, VirtualMachineTemplate, Datacenter>>()
+            {
+            }).to(AbiquoComputeServiceAdapter.class);
+        bind(new TypeLiteral<Function<VirtualMachine, NodeMetadata>>()
+        {
+        }).to(VirtualMachineToNodeMetadata.class);
+        bind(new TypeLiteral<Function<VirtualMachineTemplate, Image>>()
+        {
+        }).to(VirtualMachineTemplateToImage.class);
+        bind(new TypeLiteral<Function<VirtualMachineTemplate, Hardware>>()
+        {
+        }).to(VirtualMachineTemplateToHardware.class);
+        bind(new TypeLiteral<Function<Datacenter, Location>>()
+        {
+        }).to(DatacenterToLocation.class);
+        bind(ImplicitLocationSupplier.class).to(OnlyLocationOrFirstZone.class).in(Scopes.SINGLETON);
+        bind(TemplateOptions.class).to(AbiquoTemplateOptions.class);
+        install(new LocationsFromComputeServiceAdapterModule<VirtualMachine, VirtualMachineTemplate, VirtualMachineTemplate, Datacenter>()
+        {
+        });
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/exception/NotEnoughResourcesException.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/exception/NotEnoughResourcesException.java
new file mode 100644
index 0000000..0ffd635
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/exception/NotEnoughResourcesException.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.exception;
+
+/**
+ * Exception thrown when there are not enough resources in the infrastructure to deploy the desired
+ * template.
+ * 
+ * @author Ignasi Barrera
+ */
+public class NotEnoughResourcesException extends RuntimeException
+{
+    /** Serial UID. */
+    private static final long serialVersionUID = 1L;
+
+    public NotEnoughResourcesException()
+    {
+        super();
+    }
+
+    public NotEnoughResourcesException(final String arg0, final Throwable arg1)
+    {
+        super(arg0, arg1);
+    }
+
+    public NotEnoughResourcesException(final String arg0)
+    {
+        super(arg0);
+    }
+
+    public NotEnoughResourcesException(final Throwable arg0)
+    {
+        super(arg0);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/DatacenterToLocation.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/DatacenterToLocation.java
new file mode 100644
index 0000000..e0039fa
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/DatacenterToLocation.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationBuilder;
+import org.jclouds.domain.LocationScope;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Converts a {@link Datacenter} to a {@link Location} one.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class DatacenterToLocation implements Function<Datacenter, Location>
+{
+
+    @Override
+    public Location apply(final Datacenter datacenter)
+    {
+        LocationBuilder builder = new LocationBuilder();
+        builder.id(datacenter.getId().toString());
+        builder.description(datacenter.getName() + " [" + datacenter.getLocation() + "]");
+        builder.metadata(ImmutableMap.<String, Object> of());
+        builder.scope(LocationScope.ZONE);
+        // TODO: Convert to ISO3166 code?
+        builder.iso3166Codes(ImmutableSet.<String> of());
+
+        builder.parent(new LocationBuilder().scope(LocationScope.PROVIDER).id("abiquo")
+            .description("abiquo").build());
+
+        return builder.build();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineStateToNodeState.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineStateToNodeState.java
new file mode 100644
index 0000000..806c6ef
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineStateToNodeState.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.NodeMetadata.Status;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.common.base.Function;
+
+/**
+ * Converts a {@link VirtualMachineState} object to a {@link Status} one.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class VirtualMachineStateToNodeState implements Function<VirtualMachineState, Status>
+{
+
+    @Override
+    public Status apply(final VirtualMachineState state)
+    {
+        switch (state)
+        {
+            case ALLOCATED:
+            case LOCKED:
+            case CONFIGURED:
+                return Status.PENDING;
+            case ON:
+                return Status.RUNNING;
+            case OFF:
+            case PAUSED:
+                return Status.SUSPENDED;
+            case NOT_ALLOCATED:
+                // TODO: What about nodes created but still not deployed?
+                return Status.TERMINATED;
+            case UNKNOWN:
+            default:
+                return Status.UNRECOGNIZED;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToHardware.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToHardware.java
new file mode 100644
index 0000000..f29f447
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToHardware.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.VolumeBuilder;
+import org.jclouds.compute.predicates.ImagePredicates;
+
+import com.google.common.base.Function;
+
+/**
+ * Transforms a {@link VirtualMachineTemplate} into an {@link Hardware}.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class VirtualMachineTemplateToHardware implements Function<VirtualMachineTemplate, Hardware>
+{
+    /** The default core speed, 2.0Ghz. */
+    public static final double DEFAULT_CORE_SPEED = 2.0;
+
+    @Override
+    public Hardware apply(final VirtualMachineTemplate template)
+    {
+        HardwareBuilder builder = new HardwareBuilder();
+        builder.ids(template.getId().toString());
+        builder.uri(template.getURI());
+
+        builder.name(template.getName());
+        builder.processor(new Processor(template.getCpuRequired(), DEFAULT_CORE_SPEED));
+        builder.ram(template.getRamRequired());
+
+        // Currently we consider each template as a hardware profile
+        builder.supportsImage(ImagePredicates.idEquals(template.getId().toString()));
+
+        VolumeBuilder volumeBuilder = new VolumeBuilder();
+        volumeBuilder.bootDevice(true);
+        volumeBuilder.size(toGb(template.getHdRequired()));
+        volumeBuilder.type(Volume.Type.LOCAL);
+        volumeBuilder.durable(false);
+        builder.volume(volumeBuilder.build());
+
+        return builder.build();
+    }
+
+    private static float toGb(final long bytes)
+    {
+        return bytes / 1024 / 1024 / (float) 1024;
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToImage.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToImage.java
new file mode 100644
index 0000000..7e45e68
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToImage.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import java.net.URI;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.Image.Status;
+import org.jclouds.compute.domain.ImageBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+
+import com.abiquo.model.rest.RESTLink;
+import com.google.common.base.Function;
+
+/**
+ * Transforms a {@link VirtualMachineTemplate} into an {@link Image}.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class VirtualMachineTemplateToImage implements Function<VirtualMachineTemplate, Image>
+{
+
+    @Override
+    public Image apply(final VirtualMachineTemplate template)
+    {
+        ImageBuilder builder = new ImageBuilder();
+        builder.ids(template.getId().toString());
+        builder.name(template.getName());
+        builder.description(template.getDescription());
+
+        // Only conversions have a status
+        builder.status(Status.AVAILABLE);
+        builder.backendStatus(Status.AVAILABLE.name()); // Abiquo images do not have a status
+
+        RESTLink downloadLink = template.unwrap().searchLink("diskfile");
+        builder.uri(downloadLink == null ? null : URI.create(downloadLink.getHref()));
+
+        // TODO: Operating system not implemented in Abiquo Templates
+        builder.operatingSystem(OperatingSystem.builder().description(template.getName()).build());
+        // TODO: image credentials
+        return builder.build();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineToNodeMetadata.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineToNodeMetadata.java
new file mode 100644
index 0000000..b7cbe8c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/functions/VirtualMachineToNodeMetadata.java
@@ -0,0 +1,156 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.transform;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.AuthorizationException;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+
+/**
+ * Links a {@link VirtualMachine} object to a {@link NodeMetadata} one.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, NodeMetadata>
+{
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    private final VirtualMachineTemplateToImage virtualMachineTemplateToImage;
+
+    private final VirtualMachineTemplateToHardware virtualMachineTemplateToHardware;
+
+    private final VirtualMachineStateToNodeState virtualMachineStateToNodeState;
+
+    private final DatacenterToLocation datacenterToLocation;
+
+    @Inject
+    public VirtualMachineToNodeMetadata(
+        final VirtualMachineTemplateToImage virtualMachineTemplateToImage,
+        final VirtualMachineTemplateToHardware virtualMachineTemplateToHardware,
+        final VirtualMachineStateToNodeState virtualMachineStateToNodeState,
+        final DatacenterToLocation datacenterToLocation)
+    {
+        this.virtualMachineTemplateToImage =
+            checkNotNull(virtualMachineTemplateToImage, "virtualMachineTemplateToImage");
+        this.virtualMachineTemplateToHardware =
+            checkNotNull(virtualMachineTemplateToHardware, "virtualMachineTemplateToHardware");
+        this.virtualMachineStateToNodeState =
+            checkNotNull(virtualMachineStateToNodeState, "virtualMachineStateToNodeState");
+        this.datacenterToLocation = checkNotNull(datacenterToLocation, "datacenterToLocation");
+    }
+
+    @Override
+    public NodeMetadata apply(final VirtualMachine vm)
+    {
+        NodeMetadataBuilder builder = new NodeMetadataBuilder();
+        builder.ids(vm.getId().toString());
+        builder.uri(vm.getURI());
+        builder.name(vm.getNameLabel());
+        builder.group(vm.getVirtualAppliance().getName());
+
+        // TODO: builder.credentials() (http://jira.abiquo.com/browse/ABICLOUDPREMIUM-3647)
+        VirtualDatacenter vdc = vm.getVirtualDatacenter();
+
+        // Location details
+        try
+        {
+            Datacenter datacenter = vdc.getDatacenter();
+            builder.location(datacenterToLocation.apply(datacenter));
+        }
+        catch (AuthorizationException ex)
+        {
+            logger.debug("User does not have permissions to see the location of the node");
+        }
+
+        // Image details
+        VirtualMachineTemplate template = vm.getTemplate();
+        Image image = virtualMachineTemplateToImage.apply(template);
+        builder.imageId(image.getId().toString());
+        builder.operatingSystem(image.getOperatingSystem());
+
+        // Hardware details
+        Hardware defaultHardware = virtualMachineTemplateToHardware.apply(template);
+        Hardware hardware =
+            new HardwareBuilder() //
+                .ids(defaultHardware.getId()) //
+                .uri(defaultHardware.getUri()) //
+                .name(defaultHardware.getName()) //
+                .supportsImage(defaultHardware.supportsImage()) //
+                .ram(vm.getRam()) //
+                .hypervisor(vdc.getHypervisorType().name()) //
+                .processor(
+                    new Processor(vm.getCpu(), VirtualMachineTemplateToHardware.DEFAULT_CORE_SPEED)) //
+                .build();
+        builder.hardware(hardware);
+
+        // Networking configuration
+        List<Ip< ? , ? >> nics = vm.listAttachedNics();
+        builder.privateAddresses(ips(filter(nics, Predicates.instanceOf(PrivateIp.class))));
+        builder.publicAddresses(ips(filter(nics,
+            Predicates.not(Predicates.instanceOf(PrivateIp.class)))));
+
+        // Node state
+        VirtualMachineState state = vm.getState();
+        builder.status(virtualMachineStateToNodeState.apply(state));
+        builder.backendStatus(state.name());
+
+        return builder.build();
+    }
+
+    private static Iterable<String> ips(final Iterable<Ip< ? , ? >> nics)
+    {
+        return transform(nics, new Function<Ip< ? , ? >, String>()
+        {
+            @Override
+            public String apply(final Ip< ? , ? > nic)
+            {
+                return nic.getIp();
+            }
+        });
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/options/AbiquoTemplateOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/options/AbiquoTemplateOptions.java
new file mode 100644
index 0000000..e003474
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/options/AbiquoTemplateOptions.java
@@ -0,0 +1,257 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.options;
+
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.Network;
+import org.jclouds.abiquo.domain.network.UnmanagedNetwork;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.options.TemplateOptions;
+
+/**
+ * Contains options supported by the
+ * {@link ComputeService#createNodesInGroup(String, int, TemplateOptions)} and
+ * {@link ComputeService#createNodesInGroup(String, int, TemplateOptions)} operations on the
+ * <em>Abiquo</em> provider.
+ * 
+ * @author Ignasi Barrera
+ */
+public class AbiquoTemplateOptions extends TemplateOptions implements Cloneable
+{
+    public static final AbiquoTemplateOptions NONE = new AbiquoTemplateOptions();
+
+    private Integer overrideCores;
+
+    private Integer overrideRam;
+
+    private String vncPassword;
+
+    private String virtualDatacenter;
+
+    private Ip< ? , ? >[] ips;
+
+    private UnmanagedNetwork[] unmanagedIps;
+
+    private Network< ? > gatewayNetwork;
+
+    @Override
+    public TemplateOptions clone()
+    {
+        AbiquoTemplateOptions options = new AbiquoTemplateOptions();
+        copyTo(options);
+        return options;
+    }
+
+    @Override
+    public void copyTo(final TemplateOptions to)
+    {
+        super.copyTo(to);
+        if (to instanceof AbiquoTemplateOptions)
+        {
+            AbiquoTemplateOptions options = AbiquoTemplateOptions.class.cast(to);
+            options.overrideCores(overrideCores);
+            options.overrideRam(overrideRam);
+            options.vncPassword(vncPassword);
+            options.virtualDatacenter(virtualDatacenter);
+            options.ips(ips);
+        }
+    }
+
+    /**
+     * Override the number of cores set by the hardware profile.
+     * 
+     * @return The template options with the number of cores.
+     */
+    public AbiquoTemplateOptions overrideCores(final Integer overrideCores)
+    {
+        this.overrideCores = overrideCores;
+        return this;
+    }
+
+    public Integer getOverrideCores()
+    {
+        return overrideCores;
+    }
+
+    /**
+     * Override the amount of ram set by the hardware profile.
+     * 
+     * @return The template options with the amount of ram.
+     */
+    public AbiquoTemplateOptions overrideRam(final Integer overrideRam)
+    {
+        this.overrideRam = overrideRam;
+        return this;
+    }
+
+    public Integer getOverrideRam()
+    {
+        return overrideRam;
+    }
+
+    /**
+     * Set the VNC password to access the virtual machine.
+     * <p>
+     * By default virtual machines does not have VNC access password protected.
+     * 
+     * @return The template options with the VNC password.
+     */
+    public AbiquoTemplateOptions vncPassword(final String vncPassword)
+    {
+        this.vncPassword = vncPassword;
+        return this;
+    }
+
+    public String getVncPassword()
+    {
+        return vncPassword;
+    }
+
+    /**
+     * Set the virtual datacenter where the virtual machine must be deployed.
+     * 
+     * @return The template options with the virtual machine must be deployed.
+     */
+    public AbiquoTemplateOptions virtualDatacenter(final String virtualDatacenter)
+    {
+        this.virtualDatacenter = virtualDatacenter;
+        return this;
+    }
+
+    public String getVirtualDatacenter()
+    {
+        return virtualDatacenter;
+    }
+
+    /**
+     * Set the ip addresses for the virtual machine.
+     * 
+     * @return The template options with the ip addresses configuration.
+     */
+    public AbiquoTemplateOptions ips(final Ip< ? , ? >... ips)
+    {
+        this.ips = ips;
+        return this;
+    }
+
+    public Ip< ? , ? >[] getIps()
+    {
+        return ips;
+    }
+
+    /**
+     * Set the ip addresses that must be selected from unmanaged networks.
+     * 
+     * @return The template options with the ip addresses that must be selected from unmanaged
+     *         networks.
+     */
+    public AbiquoTemplateOptions unmanagedIps(final UnmanagedNetwork... unmanagedIps)
+    {
+        this.unmanagedIps = unmanagedIps;
+        return this;
+    }
+
+    public UnmanagedNetwork[] getUnmanagedIps()
+    {
+        return unmanagedIps;
+    }
+
+    /**
+     * Set the gateway network for the virtual machine.
+     * 
+     * @return The template options with the gateway network configuration.
+     */
+    public AbiquoTemplateOptions gatewayNetwork(final Network< ? > gatewayNetwork)
+    {
+        this.gatewayNetwork = gatewayNetwork;
+        return this;
+    }
+
+    public Network< ? > getGatewayNetwork()
+    {
+        return gatewayNetwork;
+    }
+
+    public static class Builder
+    {
+        /**
+         * @see AbiquoTemplateOptions#overrideCores(int)
+         */
+        public static AbiquoTemplateOptions overrideCores(final Integer overrideCores)
+        {
+            AbiquoTemplateOptions options = new AbiquoTemplateOptions();
+            return options.overrideCores(overrideCores);
+        }
+
+        /**
+         * @see AbiquoTemplateOptions#overrideRam(int)
+         */
+        public static AbiquoTemplateOptions overrideRam(final Integer overrideRam)
+        {
+            AbiquoTemplateOptions options = new AbiquoTemplateOptions();
+            return options.overrideRam(overrideRam);
+        }
+
+        /**
+         * @see AbiquoTemplateOptions#vncPassword(String)
+         */
+        public static AbiquoTemplateOptions vncPassword(final String vncPassword)
+        {
+            AbiquoTemplateOptions options = new AbiquoTemplateOptions();
+            return options.vncPassword(vncPassword);
+        }
+
+        /**
+         * @see AbiquoTemplateOptions#virtualDatacenter(String)
+         */
+        public static AbiquoTemplateOptions virtualDatacenter(final String virtualDatacenter)
+        {
+            AbiquoTemplateOptions options = new AbiquoTemplateOptions();
+            return options.virtualDatacenter(virtualDatacenter);
+        }
+
+        /**
+         * @see AbiquoTemplateOptions#ips(Ip...)
+         */
+        public static AbiquoTemplateOptions ips(final Ip< ? , ? >... ips)
+        {
+            AbiquoTemplateOptions options = new AbiquoTemplateOptions();
+            return options.ips(ips);
+        }
+
+        /**
+         * @see AbiquoTemplateOptions#unmanagedIps(UnmanagedNetwork...)
+         */
+        public AbiquoTemplateOptions unmanagedIps(final UnmanagedNetwork... unmanagedIps)
+        {
+            AbiquoTemplateOptions options = new AbiquoTemplateOptions();
+            return options.unmanagedIps(unmanagedIps);
+        }
+
+        /**
+         * @see AbiquoTemplateOptions#gatewayNetwork(Network)
+         */
+        public static AbiquoTemplateOptions gatewayNetwork(final Network< ? > gatewayNetwork)
+        {
+            AbiquoTemplateOptions options = new AbiquoTemplateOptions();
+            return options.gatewayNetwork(gatewayNetwork);
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceAdapter.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceAdapter.java
new file mode 100644
index 0000000..b8f0e52
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceAdapter.java
@@ -0,0 +1,251 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.strategy;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.compute.options.AbiquoTemplateOptions;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.features.services.AdministrationService;
+import org.jclouds.abiquo.features.services.CloudService;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.monitor.VirtualMachineMonitor;
+import org.jclouds.abiquo.predicates.cloud.VirtualAppliancePredicates;
+import org.jclouds.abiquo.predicates.cloud.VirtualMachineTemplatePredicates;
+import org.jclouds.abiquo.predicates.infrastructure.DatacenterPredicates;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.common.base.Predicate;
+
+/**
+ * Defines the connection between the {@link AbiquoApi} implementation and the jclouds
+ * {@link ComputeService}.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AbiquoComputeServiceAdapter
+    implements
+    ComputeServiceAdapter<VirtualMachine, VirtualMachineTemplate, VirtualMachineTemplate, Datacenter>
+{
+    @Resource
+    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+    protected Logger logger = Logger.NULL;
+
+    private final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    private final AdministrationService adminService;
+
+    private final CloudService cloudService;
+
+    private final MonitoringService monitoringService;
+
+    private AbiquoComputeServiceHelper helper;
+
+    @Inject
+    public AbiquoComputeServiceAdapter(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final AdministrationService adminService, final CloudService cloudService,
+        final MonitoringService monitoringService, final AbiquoComputeServiceHelper helper)
+    {
+        super();
+        this.context = checkNotNull(context, "context");
+        this.adminService = checkNotNull(adminService, "adminService");
+        this.cloudService = checkNotNull(cloudService, "cloudService");
+        this.monitoringService = checkNotNull(monitoringService, "monitoringService");
+        this.helper = checkNotNull(helper, "helper");
+    }
+
+    @Override
+    public NodeAndInitialCredentials<VirtualMachine> createNodeWithGroupEncodedIntoName(
+        final String tag, final String name, final Template template)
+    {
+        AbiquoTemplateOptions options = template.getOptions().as(AbiquoTemplateOptions.class);
+
+        User user = adminService.getCurrentUser();
+        Enterprise enterprise = adminService.getCurrentEnterprise();
+
+        Datacenter datacenter =
+            enterprise.findAllowedDatacenter(DatacenterPredicates.id(Integer.valueOf(template
+                .getLocation().getId())));
+
+        VirtualMachineTemplate virtualMachineTemplate =
+            enterprise.getTemplateInRepository(datacenter,
+                Integer.valueOf(template.getImage().getId()));
+
+        VirtualDatacenter vdc =
+            helper.getOrCreateVirtualDatacenter(user, enterprise, datacenter,
+                virtualMachineTemplate, options);
+
+        // Load the virtual appliance or create it
+        VirtualAppliance vapp = vdc.findVirtualAppliance(VirtualAppliancePredicates.name(tag));
+        if (vapp == null)
+        {
+            vapp = VirtualAppliance.builder(context, vdc).name(tag).build();
+            vapp.save();
+        }
+
+        Integer overrideCores = options.getOverrideCores();
+        Integer overrideRam = options.getOverrideRam();
+
+        VirtualMachine vm = VirtualMachine.builder(context, vapp, virtualMachineTemplate) //
+            .nameLabel(name) //
+            .cpu(overrideCores != null ? overrideCores : totalCores(template.getHardware())) //
+            .ram(overrideRam != null ? overrideRam : template.getHardware().getRam()) //
+            .password(options.getVncPassword()) // Can be null
+            .build();
+
+        vm.save();
+
+        // Once the virtual machine is created, override the default network settings if needed
+        helper.configureNetwork(vm, options.getGatewayNetwork(), options.getIps() == null ? null
+            : Arrays.asList(options.getIps()),
+            options.getUnmanagedIps() == null ? null : Arrays.asList(options.getUnmanagedIps()));
+
+        VirtualMachineMonitor monitor = monitoringService.getVirtualMachineMonitor();
+        vm.deploy();
+        monitor.awaitCompletionDeploy(vm);
+
+        return new NodeAndInitialCredentials<VirtualMachine>(vm, vm.getId().toString(), template
+            .getImage().getDefaultCredentials());
+    }
+
+    @Override
+    public Iterable<VirtualMachineTemplate> listHardwareProfiles()
+    {
+        // Abiquo does not have the hardwre profiles concept. Users can consume CPU and RAM
+        // resources limited only by the Enterprise or Virtual datacenter limits.
+        return listImages();
+    }
+
+    @Override
+    public Iterable<VirtualMachineTemplate> listImages()
+    {
+        Enterprise enterprise = adminService.getCurrentEnterprise();
+        return enterprise.listTemplates();
+    }
+
+    @Override
+    public VirtualMachineTemplate getImage(final String id)
+    {
+        Enterprise enterprise = adminService.getCurrentEnterprise();
+        return enterprise.findTemplate(VirtualMachineTemplatePredicates.id(Integer.valueOf(id)));
+    }
+
+    @Override
+    public Iterable<Datacenter> listLocations()
+    {
+        Enterprise enterprise = adminService.getCurrentEnterprise();
+        return enterprise.listAllowedDatacenters();
+    }
+
+    @Override
+    public VirtualMachine getNode(final String id)
+    {
+        // FIXME: Try to avoid calling the cloudService.findVirtualMachine. Navigate the hierarchy
+        // instead.
+        return cloudService.findVirtualMachine(vmId(id));
+    }
+
+    @Override
+    public void destroyNode(final String id)
+    {
+        VirtualMachine vm = getNode(id);
+        vm.delete();
+    }
+
+    @Override
+    public void rebootNode(final String id)
+    {
+        VirtualMachineMonitor monitor = monitoringService.getVirtualMachineMonitor();
+        VirtualMachine vm = getNode(id);
+        vm.reboot();
+        monitor.awaitState(VirtualMachineState.ON, vm);
+    }
+
+    @Override
+    public void resumeNode(final String id)
+    {
+        VirtualMachineMonitor monitor = monitoringService.getVirtualMachineMonitor();
+        VirtualMachine vm = getNode(id);
+        vm.changeState(VirtualMachineState.ON);
+        monitor.awaitState(VirtualMachineState.ON, vm);
+    }
+
+    @Override
+    public void suspendNode(final String id)
+    {
+        VirtualMachineMonitor monitor = monitoringService.getVirtualMachineMonitor();
+        VirtualMachine vm = getNode(id);
+        vm.changeState(VirtualMachineState.PAUSED);
+        monitor.awaitState(VirtualMachineState.PAUSED, vm);
+    }
+
+    @Override
+    public Iterable<VirtualMachine> listNodes()
+    {
+        return cloudService.listVirtualMachines();
+    }
+
+    private static Predicate<VirtualMachine> vmId(final String id)
+    {
+        return new Predicate<VirtualMachine>()
+        {
+            @Override
+            public boolean apply(final VirtualMachine input)
+            {
+                return Integer.valueOf(id).equals(input.getId());
+            }
+        };
+    }
+
+    private static int totalCores(final Hardware hardware)
+    {
+        double cores = 0;
+        for (Processor processor : hardware.getProcessors())
+        {
+            cores += processor.getCores();
+        }
+        return Double.valueOf(cores).intValue();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceHelper.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceHelper.java
new file mode 100644
index 0000000..289b39c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceHelper.java
@@ -0,0 +1,256 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.strategy;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.find;
+import static com.google.common.collect.Iterables.getFirst;
+
+import java.util.List;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.compute.exception.NotEnoughResourcesException;
+import org.jclouds.abiquo.compute.options.AbiquoTemplateOptions;
+import org.jclouds.abiquo.domain.cloud.Conversion;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.Network;
+import org.jclouds.abiquo.domain.network.PrivateNetwork;
+import org.jclouds.abiquo.domain.network.UnmanagedNetwork;
+import org.jclouds.abiquo.features.services.CloudService;
+import org.jclouds.abiquo.predicates.cloud.VirtualDatacenterPredicates;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.ConversionState;
+import com.abiquo.model.enumerator.HypervisorType;
+import com.google.common.base.Predicate;
+
+/**
+ * Helper methods to perform {@link AbiquoComputeServiceAdapter} operations.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AbiquoComputeServiceHelper
+{
+    @Resource
+    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+    protected Logger logger = Logger.NULL;
+
+    private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    private CloudService cloudService;
+
+    @Inject
+    public AbiquoComputeServiceHelper(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final CloudService cloudService)
+    {
+        super();
+        this.context = checkNotNull(context, "context");
+        this.cloudService = checkNotNull(cloudService, "cloudService");
+    }
+
+    /**
+     * Gets a virtual datacenter where the given template can be deployed.
+     * <p>
+     * If no compatible virtual datacenter is found, one will be created, if possible.
+     * 
+     * @param user The current user.
+     * @param enterprise The enterprise of the current user.
+     * @param datacenter The datacenter of the template.
+     * @param template The template to deploy.
+     * @param options The template options
+     * @return The virtual datacenter to be used to deploy the template or <code>null</code> if none
+     *         was found and a compatible one could not be created.
+     */
+    public VirtualDatacenter getOrCreateVirtualDatacenter(final User user,
+        final Enterprise enterprise, final Datacenter datacenter,
+        final VirtualMachineTemplate template, final AbiquoTemplateOptions options)
+    {
+        Iterable<VirtualDatacenter> compatibles =
+            findCompatibleVirtualDatacenters(datacenter, template);
+
+        VirtualDatacenter vdc =
+            options.getVirtualDatacenter() == null ? getFirst(compatibles, null) : find(
+                compatibles, VirtualDatacenterPredicates.name(options.getVirtualDatacenter()));
+
+        if (vdc == null)
+        {
+            vdc =
+                createCompatibleVirtualDatacenter(user, enterprise, datacenter, template,
+                    options.getVirtualDatacenter());
+            if (vdc == null)
+            {
+                throw new NotEnoughResourcesException("There are not resources to deploy the given template");
+            }
+        }
+
+        return vdc;
+    }
+
+    /**
+     * Find the virtual datacenters compatible with the given template.
+     * 
+     * @param datacenter The datacenter of the template.
+     * @param template The template to deploy.
+     * @return The virtual datacenters compatible with the given template.
+     */
+    public Iterable<VirtualDatacenter> findCompatibleVirtualDatacenters(
+        final Datacenter datacenter, final VirtualMachineTemplate template)
+    {
+        Iterable<VirtualDatacenter> vdcs =
+            cloudService.listVirtualDatacenters(VirtualDatacenterPredicates.datacenter(datacenter));
+
+        return filter(vdcs, new Predicate<VirtualDatacenter>()
+        {
+            @Override
+            public boolean apply(final VirtualDatacenter vdc)
+            {
+                return isTemplateCompatibleWithHypervisor(template, vdc.getHypervisorType());
+            }
+        });
+    }
+
+    /**
+     * Configure networking resources for the given virtual machine.
+     * 
+     * @param vm The virtual machine to configure.
+     * @param gatewayNetwork The network to be used as a gateway.
+     * @param ips The ips to attach to the virtual machine.
+     */
+    public void configureNetwork(final VirtualMachine vm,
+        @Nullable final Network< ? > gatewayNetwork,
+        @Nullable final List<Ip< ? , ? extends Network< ? >>> ips,
+        @Nullable final List<UnmanagedNetwork> unmanagedIps)
+    {
+        if (ips != null)
+        {
+            // TODO: External ips don't have the right link
+            // (http://jira.abiquo.com/browse/ABICLOUDPREMIUM-3650)
+
+            if (gatewayNetwork == null)
+            {
+                // By default the network of the first ip will be used as a gateway
+                vm.setNics(ips, unmanagedIps);
+            }
+            else
+            {
+                vm.setNics(gatewayNetwork, ips, unmanagedIps);
+            }
+        }
+    }
+
+    /**
+     * Create a new virtual datacenter compatible with the given template.
+     * 
+     * @param user The current user.
+     * @param enterprise The enterprise of the current user.
+     * @param datacenter The datacenter of the template.
+     * @param template The template to deploy.
+     * @return
+     */
+    private VirtualDatacenter createCompatibleVirtualDatacenter(final User user,
+        final Enterprise enterprise, final Datacenter datacenter,
+        final VirtualMachineTemplate template, final String name)
+    {
+        PrivateNetwork defaultNetwork =
+            PrivateNetwork.builder(context).name("DefaultNetwork").gateway("192.168.1.1")
+                .address("192.168.1.0").mask(24).build();
+
+        VirtualDatacenter vdc =
+            VirtualDatacenter.builder(context, datacenter, enterprise).network(defaultNetwork)
+                .build();
+
+        // Find the first hypervisor in the datacenter compatible with the template
+        for (HypervisorType type : HypervisorType.values())
+        {
+            if (isTemplateCompatibleWithHypervisor(template, type))
+            {
+                try
+                {
+                    logger.info("Trying to create a virtual datacenter of type %s", type.name());
+                    vdc.setName(name != null ? name : "JC-" + type.name());
+                    vdc.setHypervisorType(type);
+                    vdc.save();
+
+                    logger.info("Virtual datacenter created");
+
+                    return vdc;
+                }
+                catch (AbiquoException ex)
+                {
+                    // Just catch the error thrown when no hypervisors of the given type are
+                    // available in the datacenter
+                    if (ex.hasError("VDC-1"))
+                    {
+                        continue;
+                    }
+                    else
+                    {
+                        throw ex;
+                    }
+                }
+            }
+        }
+
+        logger.warn("Could not create a compatible virtual datacenter for template of type %s",
+            template.getDiskFormatType().name());
+
+        return null;
+    }
+
+    /**
+     * Check if the given template type is compatible with the given hypervisor type.
+     * 
+     * @param template The template to check.
+     * @param type The type of the hypervisor.
+     * @return Boolean indicating if the given template type is compatible with the given hypervisor
+     *         type.
+     */
+    private static boolean isTemplateCompatibleWithHypervisor(
+        final VirtualMachineTemplate template, final HypervisorType type)
+    {
+        boolean compatible = type.isCompatible(template.getDiskFormatType());
+        if (!compatible)
+        {
+            List<Conversion> compatibleConversions =
+                template.listConversions(type, ConversionState.FINISHED);
+            compatible = compatibleConversions != null && !compatibleConversions.isEmpty();
+        }
+        return compatible;
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoEdition.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoEdition.java
new file mode 100644
index 0000000..c7c88f1
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoEdition.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.config;
+
+/**
+ * The Abiquo Edition (Community or Enterprise).
+ * 
+ * @author Francesc Montserrat
+ */
+public enum AbiquoEdition
+{
+    ENTERPRISE, COMMUNITY;
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoProperties.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoProperties.java
new file mode 100644
index 0000000..bf98bc5
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoProperties.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.config;
+
+import org.jclouds.abiquo.features.services.MonitoringService;
+
+/**
+ * Configuration properties and constants used in Abiquo connections.
+ * 
+ * @author Ignasi Barrera
+ */
+public interface AbiquoProperties
+{
+    /**
+     * Boolean property indicating if the provided credential is an api token.
+     * <p>
+     * Default value: false
+     */
+    public static final String CREDENTIAL_IS_TOKEN = "abiquo.credential-is-token";
+
+    /**
+     * The delay (in ms) used between requests by the {@link MonitoringService} when monitoring
+     * asynchronous task state.
+     * <p>
+     * Default value: 5000 ms
+     */
+    public static final String ASYNC_TASK_MONITOR_DELAY = "abiquo.monitor-delay";
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoRestClientModule.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoRestClientModule.java
new file mode 100644
index 0000000..274a55c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/config/AbiquoRestClientModule.java
@@ -0,0 +1,154 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.config;
+
+import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.features.AdminApi;
+import org.jclouds.abiquo.features.AdminAsyncApi;
+import org.jclouds.abiquo.features.CloudApi;
+import org.jclouds.abiquo.features.CloudAsyncApi;
+import org.jclouds.abiquo.features.ConfigApi;
+import org.jclouds.abiquo.features.ConfigAsyncApi;
+import org.jclouds.abiquo.features.EnterpriseApi;
+import org.jclouds.abiquo.features.EnterpriseAsyncApi;
+import org.jclouds.abiquo.features.EventApi;
+import org.jclouds.abiquo.features.EventAsyncApi;
+import org.jclouds.abiquo.features.InfrastructureApi;
+import org.jclouds.abiquo.features.InfrastructureAsyncApi;
+import org.jclouds.abiquo.features.PricingApi;
+import org.jclouds.abiquo.features.PricingAsyncApi;
+import org.jclouds.abiquo.features.TaskApi;
+import org.jclouds.abiquo.features.TaskAsyncApi;
+import org.jclouds.abiquo.features.VirtualMachineTemplateApi;
+import org.jclouds.abiquo.features.VirtualMachineTemplateAsyncApi;
+import org.jclouds.abiquo.handlers.AbiquoErrorHandler;
+import org.jclouds.abiquo.rest.internal.AbiquoHttpAsyncClient;
+import org.jclouds.abiquo.rest.internal.AbiquoHttpClient;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.abiquo.suppliers.GetCurrentEnterprise;
+import org.jclouds.abiquo.suppliers.GetCurrentUser;
+import org.jclouds.collect.Memoized;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.Utils;
+import org.jclouds.rest.config.BinderUtils;
+import org.jclouds.rest.config.RestClientModule;
+import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Provides;
+
+/**
+ * Configures the Abiquo connection.
+ * 
+ * @author Ignasi Barrera
+ */
+@ConfiguresRestClient
+public class AbiquoRestClientModule extends RestClientModule<AbiquoApi, AbiquoAsyncApi>
+{
+    public static final Map<Class< ? >, Class< ? >> DELEGATE_MAP = ImmutableMap
+        .<Class< ? >, Class< ? >> builder() //
+        .put(InfrastructureApi.class, InfrastructureAsyncApi.class) //
+        .put(EnterpriseApi.class, EnterpriseAsyncApi.class) //
+        .put(AdminApi.class, AdminAsyncApi.class) //
+        .put(ConfigApi.class, ConfigAsyncApi.class) //
+        .put(CloudApi.class, CloudAsyncApi.class) //
+        .put(VirtualMachineTemplateApi.class, VirtualMachineTemplateAsyncApi.class) //
+        .put(TaskApi.class, TaskAsyncApi.class) //
+        .put(EventApi.class, EventAsyncApi.class).put(PricingApi.class, PricingAsyncApi.class) //
+        .build();
+
+    public AbiquoRestClientModule()
+    {
+        super(DELEGATE_MAP);
+    }
+
+    @Override
+    protected void bindAsyncClient()
+    {
+        super.bindAsyncClient();
+        BinderUtils.bindAsyncClient(binder(), AbiquoHttpAsyncClient.class);
+    }
+
+    @Override
+    protected void bindClient()
+    {
+        super.bindClient();
+        BinderUtils.bindClient(binder(), AbiquoHttpClient.class, AbiquoHttpAsyncClient.class,
+            ImmutableMap.<Class< ? >, Class< ? >> of(AbiquoHttpClient.class,
+                AbiquoHttpAsyncClient.class));
+    }
+
+    @Override
+    protected void configure()
+    {
+        super.configure();
+        bind(Utils.class).to(ExtendedUtils.class);
+    }
+
+    @Override
+    protected void bindErrorHandlers()
+    {
+        bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(AbiquoErrorHandler.class);
+        bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(AbiquoErrorHandler.class);
+        bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(AbiquoErrorHandler.class);
+    }
+
+    @Provides
+    @Singleton
+    @Memoized
+    public Supplier<User> getCurrentUser(
+        final AtomicReference<AuthorizationException> authException,
+        @Named(PROPERTY_SESSION_INTERVAL) final long seconds, final GetCurrentUser getCurrentUser)
+    {
+        return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException,
+            getCurrentUser, seconds, TimeUnit.SECONDS);
+    }
+
+    @Provides
+    @Singleton
+    @Memoized
+    public Supplier<Enterprise> getCurrentEnterprise(
+        final AtomicReference<AuthorizationException> authException,
+        @Named(PROPERTY_SESSION_INTERVAL) final long seconds,
+        final GetCurrentEnterprise getCurrentEnterprise)
+    {
+        return MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier.create(authException,
+            getCurrentEnterprise, seconds, TimeUnit.SECONDS);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithLimitsWrapper.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithLimitsWrapper.java
new file mode 100644
index 0000000..6983299
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithLimitsWrapper.java
@@ -0,0 +1,195 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.transport.SingleResourceWithLimitsDto;
+
+/**
+ * This class is used to decorate transport objects that have limits with high level functionality.
+ * 
+ * @author Ignasi Barrera
+ */
+public abstract class DomainWithLimitsWrapper<T extends SingleResourceWithLimitsDto> extends
+    DomainWrapper<T>
+{
+
+    protected DomainWithLimitsWrapper(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final T target)
+    {
+        super(context, target);
+    }
+
+    // Delegate methods
+
+    public int getCpuCountHardLimit()
+    {
+        return target.getCpuCountHardLimit();
+    }
+
+    public int getCpuCountSoftLimit()
+    {
+        return target.getCpuCountSoftLimit();
+    }
+
+    public long getHdHardLimitInMb()
+    {
+        return target.getHdHardLimitInMb();
+    }
+
+    public long getHdSoftLimitInMb()
+    {
+        return target.getHdSoftLimitInMb();
+    }
+
+    public long getPublicIpsHard()
+    {
+        return target.getPublicIpsHard();
+    }
+
+    public long getPublicIpsSoft()
+    {
+        return target.getPublicIpsSoft();
+    }
+
+    public int getRamHardLimitInMb()
+    {
+        return target.getRamHardLimitInMb();
+    }
+
+    public int getRamSoftLimitInMb()
+    {
+        return target.getRamSoftLimitInMb();
+    }
+
+    public long getStorageHard()
+    {
+        return target.getStorageHard();
+    }
+
+    public long getStorageSoft()
+    {
+        return target.getStorageSoft();
+    }
+
+    public long getVlansHard()
+    {
+        return target.getVlansHard();
+    }
+
+    public long getVlansSoft()
+    {
+        return target.getVlansSoft();
+    }
+
+    public void setCpuCountHardLimit(final int cpuCountHardLimit)
+    {
+        target.setCpuCountHardLimit(cpuCountHardLimit);
+    }
+
+    public void setCpuCountLimits(final int softLimit, final int hardLimit)
+    {
+        target.setCpuCountLimits(softLimit, hardLimit);
+    }
+
+    public void setCpuCountSoftLimit(final int cpuCountSoftLimit)
+    {
+        target.setCpuCountSoftLimit(cpuCountSoftLimit);
+    }
+
+    public void setHdHardLimitInMb(final long hdHardLimitInMb)
+    {
+        target.setHdHardLimitInMb(hdHardLimitInMb);
+    }
+
+    public void setHdLimitsInMb(final long softLimit, final long hardLimit)
+    {
+        target.setHdLimitsInMb(softLimit, hardLimit);
+    }
+
+    public void setHdSoftLimitInMb(final long hdSoftLimitInMb)
+    {
+        target.setHdSoftLimitInMb(hdSoftLimitInMb);
+    }
+
+    public void setPublicIPLimits(final long softLimit, final long hardLimit)
+    {
+        target.setPublicIPLimits(softLimit, hardLimit);
+    }
+
+    public void setPublicIpsHard(final long publicIpsHard)
+    {
+        target.setPublicIpsHard(publicIpsHard);
+    }
+
+    public void setPublicIpsSoft(final long publicIpsSoft)
+    {
+        target.setPublicIpsSoft(publicIpsSoft);
+    }
+
+    public void setRamHardLimitInMb(final int ramHardLimitInMb)
+    {
+        target.setRamHardLimitInMb(ramHardLimitInMb);
+    }
+
+    public void setRamLimitsInMb(final int softLimit, final int hardLimit)
+    {
+        target.setRamLimitsInMb(softLimit, hardLimit);
+    }
+
+    public void setRamSoftLimitInMb(final int ramSoftLimitInMb)
+    {
+        target.setRamSoftLimitInMb(ramSoftLimitInMb);
+    }
+
+    public void setStorageHard(final long storageHard)
+    {
+        target.setStorageHard(storageHard);
+    }
+
+    public void setStorageLimits(final long softLimit, final long hardLimit)
+    {
+        target.setStorageLimits(softLimit, hardLimit);
+    }
+
+    public void setStorageSoft(final long storageSoft)
+    {
+        target.setStorageSoft(storageSoft);
+    }
+
+    public void setVlansHard(final long vlansHard)
+    {
+        target.setVlansHard(vlansHard);
+    }
+
+    public void setVlansLimits(final long softLimit, final long hardLimit)
+    {
+        target.setVlansLimits(softLimit, hardLimit);
+    }
+
+    public void setVlansSoft(final long vlansSoft)
+    {
+        target.setVlansSoft(vlansSoft);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithTasksWrapper.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithTasksWrapper.java
new file mode 100644
index 0000000..0a599e6
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithTasksWrapper.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.abiquo.server.core.task.TaskDto;
+import com.abiquo.server.core.task.TasksDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.common.primitives.Longs;
+
+/**
+ * This class is used to decorate transport objects that are owners of some {@link TaskDto}
+ * 
+ * @author Ignasi Barrera
+ */
+public abstract class DomainWithTasksWrapper<T extends SingleResourceTransportDto> extends
+    DomainWrapper<T>
+{
+
+    protected DomainWithTasksWrapper(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final T target)
+    {
+        super(context, target);
+    }
+
+    public List<AsyncTask> listTasks()
+    {
+        TasksDto result = context.getApi().getTaskApi().listTasks(target);
+        List<AsyncTask> tasks = wrap(context, AsyncTask.class, result.getCollection());
+
+        // Return the most recent task first
+        Collections.sort(tasks, new Ordering<AsyncTask>()
+        {
+            @Override
+            public int compare(final AsyncTask left, final AsyncTask right)
+            {
+                return Longs.compare(left.getTimestamp(), right.getTimestamp());
+            }
+        }.reverse());
+
+        return tasks;
+    }
+
+    public List<AsyncTask> listTasks(final Predicate<AsyncTask> filter)
+    {
+        return Lists.newLinkedList(filter(listTasks(), filter));
+    }
+
+    public AsyncTask findTask(final Predicate<AsyncTask> filter)
+    {
+        return Iterables.getFirst(filter(listTasks(), filter), null);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWrapper.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWrapper.java
new file mode 100644
index 0000000..7ae35dc
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWrapper.java
@@ -0,0 +1,241 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+
+import java.lang.reflect.Constructor;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.exception.WrapperException;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.domain.util.LinkUtils;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.abiquo.model.transport.WrapperDto;
+import com.abiquo.server.core.task.TaskDto;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
+/**
+ * This class is used to decorate transport objects with high level functionality.
+ * 
+ * @author Francesc Montserrat
+ * @author Ignasi Barrera
+ */
+public abstract class DomainWrapper<T extends SingleResourceTransportDto>
+{
+    /** The rest context. */
+    protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    /** The wrapped object. */
+    protected T target;
+
+    protected DomainWrapper(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final T target)
+    {
+        super();
+        this.context = checkNotNull(context, "context");
+        this.target = checkNotNull(target, "target");
+    }
+
+    /**
+     * Returns the URI that identifies the transport object
+     * 
+     * @return The URI identifying the transport object
+     */
+    public URI getURI()
+    {
+        RESTLink link = LinkUtils.getSelfLink(target);
+        return link == null ? null : URI.create(link.getHref());
+    }
+
+    /**
+     * Returns the wrapped object.
+     */
+    public T unwrap()
+    {
+        return target;
+    }
+
+    /**
+     * Read the ID of the parent resource from the given link.
+     * 
+     * @param parentLinkRel The link to the parent resource.
+     * @return The ID of the parent resource.
+     */
+    protected Integer getParentId(final String parentLinkRel)
+    {
+        return target.getIdFromLink(parentLinkRel);
+    }
+
+    /**
+     * Wraps an object in the given wrapper class.
+     */
+    public static <T extends SingleResourceTransportDto, W extends DomainWrapper<T>> W wrap(
+        final RestContext<AbiquoApi, AbiquoAsyncApi> context, final Class<W> wrapperClass,
+        final T target)
+    {
+        if (target == null)
+        {
+            return null;
+        }
+
+        try
+        {
+            Constructor<W> cons =
+                wrapperClass.getDeclaredConstructor(RestContext.class, target.getClass());
+            if (!cons.isAccessible())
+            {
+                cons.setAccessible(true);
+            }
+            return cons.newInstance(context, target);
+        }
+        catch (Exception ex)
+        {
+            throw new WrapperException(wrapperClass, target, ex);
+        }
+    }
+
+    /**
+     * Wrap a collection of objects to the given wrapper class.
+     */
+    public static <T extends SingleResourceTransportDto, W extends DomainWrapper<T>> List<W> wrap(
+        final RestContext<AbiquoApi, AbiquoAsyncApi> context, final Class<W> wrapperClass,
+        final Iterable<T> targets)
+    {
+        if (targets == null)
+        {
+            return null;
+        }
+
+        return Lists.newLinkedList(transform(targets, new Function<T, W>()
+        {
+            @Override
+            public W apply(final T input)
+            {
+                return wrap(context, wrapperClass, input);
+            }
+        }));
+    }
+
+    /**
+     * Unwrap a collection of objects.
+     */
+    public static <T extends SingleResourceTransportDto, W extends DomainWrapper<T>> List<T> unwrap(
+        final Iterable<W> targets)
+    {
+        return Lists.newLinkedList(transform(targets, new Function<W, T>()
+        {
+            @Override
+            public T apply(final W input)
+            {
+                return input.unwrap();
+            }
+        }));
+    }
+
+    /**
+     * Update or creates a link of "target" with the uri of a link from "source".
+     */
+    protected <T1 extends SingleResourceTransportDto, T2 extends SingleResourceTransportDto> void updateLink(
+        final T1 target, final String targetLinkRel, final T2 source, final String sourceLinkRel)
+    {
+        RESTLink parent = null;
+
+        checkNotNull(source.searchLink(sourceLinkRel), ValidationErrors.MISSING_REQUIRED_LINK);
+
+        // Insert
+        if ((parent = target.searchLink(targetLinkRel)) == null)
+        {
+            target.addLink(new RESTLink(targetLinkRel, source.searchLink(sourceLinkRel).getHref()));
+        }
+        // Replace
+        else
+        {
+            parent.setHref(source.searchLink(sourceLinkRel).getHref());
+        }
+    }
+
+    /**
+     * Join a collection of {@link WrapperDto} objects in a single collection with all the elements
+     * of each wrapper object.
+     */
+    public static <T extends SingleResourceTransportDto> Iterable<T> join(
+        final Iterable< ? extends WrapperDto<T>> collection)
+    {
+        List<T> dtos = Lists.newLinkedList();
+        for (WrapperDto<T> wrapper : collection)
+        {
+            dtos.addAll(wrapper.getCollection());
+        }
+        return dtos;
+    }
+
+    /**
+     * Utility method to get an {@link AsyncTask} given an {@link AcceptedRequestDto}.
+     * 
+     * @param acceptedRequest The accepted request dto.
+     * @return The async task.
+     */
+    protected AsyncTask getTask(final AcceptedRequestDto<String> acceptedRequest)
+    {
+        RESTLink taskLink = acceptedRequest.getStatusLink();
+        checkNotNull(taskLink, ValidationErrors.MISSING_REQUIRED_LINK + AsyncTask.class);
+
+        // This will return null on untrackable tasks
+        TaskDto task = context.getApi().getTaskApi().getTask(taskLink);
+        return wrap(context, AsyncTask.class, task);
+    }
+
+    /**
+     * Utility method to get all {@link AsyncTask} related to an {@link AcceptedRequestDto}.
+     * 
+     * @param acceptedRequest The accepted request dto.
+     * @return The async task array.
+     */
+    protected AsyncTask[] getTasks(final AcceptedRequestDto<String> acceptedRequest)
+    {
+        List<AsyncTask> tasks = new ArrayList<AsyncTask>();
+
+        for (RESTLink link : acceptedRequest.getLinks())
+        {
+            // This will return null on untrackable tasks
+            TaskDto task = context.getApi().getTaskApi().getTask(link);
+            if (task != null)
+            {
+                tasks.add(wrap(context, AsyncTask.class, task));
+            }
+        }
+
+        AsyncTask[] taskArr = new AsyncTask[tasks.size()];
+        return tasks.toArray(taskArr);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/builder/LimitsBuilder.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/builder/LimitsBuilder.java
new file mode 100644
index 0000000..a3f045d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/builder/LimitsBuilder.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.builder;
+
+/**
+ * Base class for all builders that represent limits.
+ * 
+ * @author Ignasi Barrera
+ * @param <T> The type of the target builder.
+ */
+public abstract class LimitsBuilder<T extends LimitsBuilder<T>>
+{
+    /** The default limits for enterprises (unlimited). */
+    protected static final int DEFAULT_LIMITS = 0;
+
+    protected Integer ramSoftLimitInMb = DEFAULT_LIMITS;
+
+    protected Integer ramHardLimitInMb = DEFAULT_LIMITS;
+
+    protected Integer cpuCountSoftLimit = DEFAULT_LIMITS;
+
+    protected Integer cpuCountHardLimit = DEFAULT_LIMITS;
+
+    protected Long hdSoftLimitInMb = Long.valueOf(DEFAULT_LIMITS);
+
+    protected Long hdHardLimitInMb = Long.valueOf(DEFAULT_LIMITS);
+
+    protected Long storageSoft = Long.valueOf(DEFAULT_LIMITS);
+
+    protected Long storageHard = Long.valueOf(DEFAULT_LIMITS);
+
+    protected Long vlansSoft = Long.valueOf(DEFAULT_LIMITS);
+
+    protected Long vlansHard = Long.valueOf(DEFAULT_LIMITS);
+
+    protected Long publicIpsSoft = Long.valueOf(DEFAULT_LIMITS);
+
+    protected Long publicIpsHard = Long.valueOf(DEFAULT_LIMITS);
+
+    @SuppressWarnings("unchecked")
+    public T ramLimits(final int soft, final int hard)
+    {
+        this.ramSoftLimitInMb = soft;
+        this.ramHardLimitInMb = hard;
+        return (T) this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T cpuCountLimits(final int soft, final int hard)
+    {
+        this.cpuCountSoftLimit = soft;
+        this.cpuCountHardLimit = hard;
+        return (T) this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T hdLimitsInMb(final long soft, final long hard)
+    {
+        this.hdSoftLimitInMb = soft;
+        this.hdHardLimitInMb = hard;
+        return (T) this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T storageLimits(final long soft, final long hard)
+    {
+        this.storageSoft = soft;
+        this.storageHard = hard;
+        return (T) this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T vlansLimits(final long soft, final long hard)
+    {
+        this.vlansSoft = soft;
+        this.vlansHard = hard;
+        return (T) this;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T publicIpsLimits(final long soft, final long hard)
+    {
+        this.publicIpsSoft = soft;
+        this.publicIpsHard = hard;
+        return (T) this;
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Conversion.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Conversion.java
new file mode 100644
index 0000000..1d8fbe3
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Conversion.java
@@ -0,0 +1,163 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Date;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWithTasksWrapper;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.ConversionState;
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.appslibrary.ConversionDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to {@link ConversionDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Conversion+Resource">
+ *      http://community.abiquo.com/display/ABI20/Conversion+Resource</a>
+ */
+public class Conversion extends DomainWithTasksWrapper<ConversionDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Conversion(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final ConversionDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain methods
+
+    public void refresh()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink("edit"), ValidationErrors.MISSING_REQUIRED_LINK + "edit");
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = checkNotNull(utils.getAbiquoHttpClient().get(link), "conversion");
+
+        ParseXMLWithJAXB<ConversionDto> parser =
+            new ParseXMLWithJAXB<ConversionDto>(utils.getXml(),
+                TypeLiteral.get(ConversionDto.class));
+
+        target = parser.apply(response);
+    }
+
+    // Parent access
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Machine+Template+Resource" >
+     *      http://community.abiquo.com/display/ABI20/Virtual+Machine+Template+Resource</a>
+     */
+    public VirtualMachineTemplate getVirtualMachineTemplate()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.VIRTUAL_MACHINE_TEMPLATE),
+                ValidationErrors.MISSING_REQUIRED_LINK + " "
+                    + ParentLinkName.VIRTUAL_MACHINE_TEMPLATE);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<VirtualMachineTemplateDto> parser =
+            new ParseXMLWithJAXB<VirtualMachineTemplateDto>(utils.getXml(),
+                TypeLiteral.get(VirtualMachineTemplateDto.class));
+
+        return wrap(context, VirtualMachineTemplate.class, parser.apply(response));
+    }
+
+    /**
+     * Starts a new BPM task to regenerate a failed conversion.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Conversion+Resource#ConversionResource-UpdateConversion"
+     *      > http://community.abiquo.com/display/ABI20/Conversion+Resource#ConversionResource-
+     *      UpdateConversion</a>
+     * @return The task reference to track its progress
+     */
+    public AsyncTask restartFailedConversion()
+    {
+        return getVirtualMachineTemplate().requestConversion(getTargetFormat());
+    }
+
+    // Delegate methods
+
+    public String getSourcePath()
+    {
+        return target.getSourcePath();
+    }
+
+    public ConversionState getState()
+    {
+        return target.getState();
+    }
+
+    public String getTargetPath()
+    {
+        return target.getTargetPath();
+    }
+
+    public Long getTargetSizeInBytes()
+    {
+        return target.getTargetSizeInBytes();
+    }
+
+    public DiskFormatType getSourceFormat()
+    {
+        return target.getSourceFormat();
+    }
+
+    public DiskFormatType getTargetFormat()
+    {
+        return target.getTargetFormat();
+    }
+
+    public Date getStartTimestamp()
+    {
+        return target.getStartTimestamp();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Conversion [sourcePath=" + getSourcePath() + ", sourceFormat=" + getSourceFormat()
+            + ", targetPath=" + getTargetPath() + ", targetFormat=" + getTargetFormat()
+            + ", targetSizeInBytes=" + getTargetSizeInBytes() + ", startTimestamp="
+            + getStartTimestamp() + ", state=" + getState() + "]";
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/HardDisk.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/HardDisk.java
new file mode 100644
index 0000000..7a4af28
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/HardDisk.java
@@ -0,0 +1,181 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+
+/**
+ * Represents a disk attached to a virtual machine.
+ * <p>
+ * This disks will be created when a virtual machine is deployed, and will be destroyed when it is
+ * undeployed. If there is a need to use persistent storage, a persistent {@link Volume} should be
+ * used instead.
+ * 
+ * @author Ignasi Barrera
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Hard+Disks+Resource">
+ *      http://community.abiquo.com/display/ABI20/Hard+Disks+Resource</a>
+ */
+public class HardDisk extends DomainWrapper<DiskManagementDto>
+{
+    /** The virtual datacenter where the hard disk belongs. */
+    private VirtualDatacenter virtualDatacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected HardDisk(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final DiskManagementDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Creates the hard disk in the selected virtual datacenter.
+     * <p>
+     * Once the hard disk has been created it can be attached to a virtual machine of the virtual
+     * datacenter.
+     */
+    public void save()
+    {
+        target = context.getApi().getCloudApi().createHardDisk(virtualDatacenter.unwrap(), target);
+    }
+
+    /**
+     * Deletes the hard disk.
+     */
+    public void delete()
+    {
+        context.getApi().getCloudApi().deleteHardDisk(target);
+        target = null;
+    }
+
+    // Parent access
+
+    /**
+     * Gets the virtual datacenter where the hard disk belongs to.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-RetrieveaVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-RetrieveaVirtualDatacenter</a>
+     */
+    public VirtualDatacenter getVirtualDatacenter()
+    {
+        Integer virtualDatacenterId = target.getIdFromLink(ParentLinkName.VIRTUAL_DATACENTER);
+        VirtualDatacenterDto dto =
+            context.getApi().getCloudApi().getVirtualDatacenter(virtualDatacenterId);
+        virtualDatacenter = wrap(context, VirtualDatacenter.class, dto);
+        return virtualDatacenter;
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VirtualDatacenter virtualDatacenter)
+    {
+        return new Builder(context, virtualDatacenter);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private Long sizeInMb;
+
+        private VirtualDatacenter virtualDatacenter;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final VirtualDatacenter virtualDatacenter)
+        {
+            super();
+            checkNotNull(virtualDatacenter, ValidationErrors.NULL_RESOURCE
+                + VirtualDatacenter.class);
+            this.context = context;
+            this.virtualDatacenter = virtualDatacenter;
+        }
+
+        public Builder sizeInMb(final long sizeInMb)
+        {
+            this.sizeInMb = sizeInMb;
+            return this;
+        }
+
+        public HardDisk build()
+        {
+            DiskManagementDto dto = new DiskManagementDto();
+            dto.setSizeInMb(sizeInMb);
+
+            HardDisk hardDisk = new HardDisk(context, dto);
+            hardDisk.virtualDatacenter = virtualDatacenter;
+
+            return hardDisk;
+        }
+    }
+
+    // Delegate methods. Since a hard disk cannot be edited, setters are not visible
+
+    /**
+     * Returns the id of the hard disk.
+     */
+    public Integer getId()
+    {
+        // TODO: DiskManagementDto does not have an id field
+        return target.getEditLink() == null ? null : target.getIdFromLink("edit");
+    }
+
+    /**
+     * Returns the size of the hard disk in MB.
+     */
+    public Long getSizeInMb()
+    {
+        return target.getSizeInMb();
+    }
+
+    /**
+     * Returns the sequence number of the hard disk.
+     * <p>
+     * It will be computed when attaching the hard disk to a virtual machine and will determine the
+     * attachment order of the disk in the virtual machine.
+     */
+    public Integer getSequence()
+    {
+        return target.getSequence();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "HardDisk [id=" + getId() + ", sizeInMb=" + getSizeInMb() + ", sequence="
+            + getSequence() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualAppliance.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualAppliance.java
new file mode 100644
index 0000000..71ebcd1
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualAppliance.java
@@ -0,0 +1,403 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualApplianceState;
+import com.abiquo.server.core.cloud.VirtualApplianceStateDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.cloud.VirtualMachineTaskDto;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Represents a virtual appliance.
+ * <p>
+ * A virtual appliance is a logic container for virtual machines that together make an appliance.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Virtual+Appliance+Resource">
+ *      http://community.abiquo.com/display/ABI20/Virtual+Appliance+Resource</a>
+ */
+public class VirtualAppliance extends DomainWrapper<VirtualApplianceDto>
+{
+    /** The virtual datacenter where the virtual appliance belongs. */
+    private VirtualDatacenter virtualDatacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected VirtualAppliance(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VirtualApplianceDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Deletes the virtual appliance.
+     */
+    public void delete()
+    {
+        context.getApi().getCloudApi().deleteVirtualAppliance(target);
+        target = null;
+    }
+
+    /**
+     * Creates the virtual appliance in the selected virtual datacenter.
+     */
+    public void save()
+    {
+        target =
+            context.getApi().getCloudApi()
+                .createVirtualAppliance(virtualDatacenter.unwrap(), target);
+    }
+
+    /**
+     * Updates the virtual appliance information when some of its properties have changed.
+     */
+    public void update()
+    {
+        target = context.getApi().getCloudApi().updateVirtualAppliance(target);
+    }
+
+    // Parent access
+
+    /**
+     * Gets the virtual datacenter where the virtual appliance belongs to.
+     * 
+     * @resturn The virtual datacenter where the virtual appliance belongs to.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-RetrieveaVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-RetrieveaVirtualDatacenter</a>
+     */
+    public VirtualDatacenter getVirtualDatacenter()
+    {
+        Integer virtualDatacenterId = target.getIdFromLink(ParentLinkName.VIRTUAL_DATACENTER);
+        VirtualDatacenterDto dto =
+            context.getApi().getCloudApi().getVirtualDatacenter(virtualDatacenterId);
+        virtualDatacenter = wrap(context, VirtualDatacenter.class, dto);
+        return virtualDatacenter;
+    }
+
+    /**
+     * Gets the enterprise where the virtual appliance belongs to.
+     * 
+     * @return The enterprise where the virtual appliance belongs to.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-RetrieveaEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-
+     *      RetrieveaEnterprise</a>
+     */
+    public Enterprise getEnterprise()
+    {
+        Integer enterpriseId = target.getIdFromLink(ParentLinkName.ENTERPRISE);
+        EnterpriseDto dto = context.getApi().getEnterpriseApi().getEnterprise(enterpriseId);
+        return wrap(context, Enterprise.class, dto);
+    }
+
+    /**
+     * Gets the current state of the virtual appliance.
+     * 
+     * @return The current state of the virtual appliance.
+     */
+    public VirtualApplianceState getState()
+    {
+        VirtualApplianceStateDto stateDto =
+            context.getApi().getCloudApi().getVirtualApplianceState(target);
+        return stateDto.getPower();
+    }
+
+    // Children access
+
+    /**
+     * Gets the list of virtual machines in the virtual appliance.
+     * 
+     * @return The list of virtual machines in the virtual appliance.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI18/Virtual+Machine+Resource#VirtualMachineResource-RetrievethelistofVirtualMachines."
+     *      >
+     *      http://community.abiquo.com/display/ABI18/Virtual+Machine+Resource#VirtualMachineResource
+     *      -RetrievethelistofVirtualMachines.</a>
+     */
+    public List<VirtualMachine> listVirtualMachines()
+    {
+        return listVirtualMachines(VirtualMachineOptions.builder().disablePagination().build());
+    }
+
+    /**
+     * Gets the list of virtual machines in the virtual appliance.
+     * 
+     * @return The list of virtual machines in the virtual appliance.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI18/Virtual+Machine+Resource#VirtualMachineResource-RetrievethelistofVirtualMachines."
+     *      >
+     *      http://community.abiquo.com/display/ABI18/Virtual+Machine+Resource#VirtualMachineResource
+     *      -RetrievethelistofVirtualMachines.</a>
+     */
+    public List<VirtualMachine> listVirtualMachines(final VirtualMachineOptions options)
+    {
+        VirtualMachinesWithNodeExtendedDto vms =
+            context.getApi().getCloudApi().listVirtualMachines(target, options);
+        return wrap(context, VirtualMachine.class, vms.getCollection());
+    }
+
+    /**
+     * Gets the list of virtual machines in the virtual appliance matching the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The list of virtual machines in the virtual appliance matching the given filter.
+     */
+    public List<VirtualMachine> listVirtualMachines(final Predicate<VirtualMachine> filter)
+    {
+        return Lists.newLinkedList(filter(listVirtualMachines(), filter));
+    }
+
+    /**
+     * Gets a single virtual machine in the virtual appliance matching the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The virtual machine or <code>null</code> if none matched the given filter.
+     */
+    public VirtualMachine findVirtualMachine(final Predicate<VirtualMachine> filter)
+    {
+        return Iterables.getFirst(filter(listVirtualMachines(), filter), null);
+    }
+
+    /**
+     * Gets a concrete virtual machine in the virtual appliance.
+     * 
+     * @param id The id of the virtual machine.
+     * @return The requested virtual machine.
+     */
+    public VirtualMachine getVirtualMachine(final Integer id)
+    {
+        VirtualMachineWithNodeExtendedDto vm =
+            context.getApi().getCloudApi().getVirtualMachine(target, id);
+        return wrap(context, VirtualMachine.class, vm);
+    }
+
+    // Actions
+
+    /**
+     * Deploys the virtual appliance.
+     * <p>
+     * This method will start the deployment of all the virtual machines in the virtual appliance,
+     * and will return an {@link AsyncTask} reference for each deployment operation. The deployment
+     * will finish when all individual tasks finish.
+     * 
+     * @return The list of tasks corresponding to the deploy process of each virtual machine in the
+     *         appliance.
+     */
+    public AsyncTask[] deploy()
+    {
+        return deploy(false);
+    }
+
+    /**
+     * Deploys the virtual appliance.
+     * <p>
+     * This method will start the deployment of all the virtual machines in the virtual appliance,
+     * and will return an {@link AsyncTask} reference for each deploy operation. The deployment will
+     * finish when all individual tasks finish.
+     * 
+     * @param forceEnterpriseSoftLimits Boolean indicating if the deployment must be executed even
+     *            if the enterprise soft limits are reached.
+     * @return The list of tasks corresponding to the deploy process of each virtual machine in the
+     *         appliance.
+     */
+    public AsyncTask[] deploy(final boolean forceEnterpriseSoftLimits)
+    {
+        VirtualMachineTaskDto force = new VirtualMachineTaskDto();
+        force.setForceEnterpriseSoftLimits(forceEnterpriseSoftLimits);
+
+        AcceptedRequestDto<String> response =
+            context.getApi().getCloudApi().deployVirtualAppliance(unwrap(), force);
+
+        return getTasks(response);
+    }
+
+    /**
+     * Undeploys the virtual appliance.
+     * <p>
+     * This method will start the undeploy of all the virtual machines in the virtual appliance, and
+     * will return an {@link AsyncTask} reference for each undeploy operation. The undeploy will
+     * finish when all individual tasks finish.
+     * 
+     * @return The list of tasks corresponding to the undeploy process of each virtual machine in
+     *         the appliance.
+     */
+    public AsyncTask[] undeploy()
+    {
+        return undeploy(false);
+    }
+
+    /**
+     * Undeploys the virtual appliance.
+     * <p>
+     * This method will start the undeploy of all the virtual machines in the virtual appliance, and
+     * will return an {@link AsyncTask} reference for each undeploy operation. The undeploy will
+     * finish when all individual tasks finish.
+     * 
+     * @param forceUndeploy Boolean flag to force the undeploy even if the virtual appliance
+     *            contains imported virtual machines.
+     * @return The list of tasks corresponding to the undeploy process of each virtual machine in
+     *         the appliance.
+     */
+    public AsyncTask[] undeploy(final boolean forceUndeploy)
+    {
+        VirtualMachineTaskDto force = new VirtualMachineTaskDto();
+        force.setForceUndeploy(forceUndeploy);
+
+        AcceptedRequestDto<String> response =
+            context.getApi().getCloudApi().undeployVirtualAppliance(unwrap(), force);
+
+        return getTasks(response);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VirtualDatacenter virtualDatacenter)
+    {
+        return new Builder(context, virtualDatacenter);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name;
+
+        private VirtualDatacenter virtualDatacenter;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final VirtualDatacenter virtualDatacenter)
+        {
+            super();
+            checkNotNull(virtualDatacenter, ValidationErrors.NULL_RESOURCE
+                + VirtualDatacenter.class);
+            this.virtualDatacenter = virtualDatacenter;
+            this.context = context;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder virtualDatacenter(final VirtualDatacenter virtualDatacenter)
+        {
+            checkNotNull(virtualDatacenter, ValidationErrors.NULL_RESOURCE
+                + VirtualDatacenter.class);
+            this.virtualDatacenter = virtualDatacenter;
+            return this;
+        }
+
+        public VirtualAppliance build()
+        {
+            VirtualApplianceDto dto = new VirtualApplianceDto();
+            dto.setName(name);
+
+            VirtualAppliance virtualAppliance = new VirtualAppliance(context, dto);
+            virtualAppliance.virtualDatacenter = virtualDatacenter;
+
+            return virtualAppliance;
+        }
+
+        public static Builder fromVirtualAppliance(final VirtualAppliance in)
+        {
+            return VirtualAppliance.builder(in.context, in.virtualDatacenter).name(in.getName());
+        }
+    }
+
+    // Delegate methods
+
+    public int getError()
+    {
+        return target.getError();
+    }
+
+    public int getHighDisponibility()
+    {
+        return target.getHighDisponibility();
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public int getPublicApp()
+    {
+        return target.getPublicApp();
+    }
+
+    public void setHighDisponibility(final int highDisponibility)
+    {
+        target.setHighDisponibility(highDisponibility);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setPublicApp(final int publicApp)
+    {
+        target.setPublicApp(publicApp);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "VirtualAppliance [id=" + getId() + ", name=" + getName() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualDatacenter.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualDatacenter.java
new file mode 100644
index 0000000..b95c591
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualDatacenter.java
@@ -0,0 +1,680 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.DomainWithLimitsWrapper;
+import org.jclouds.abiquo.domain.builder.LimitsBuilder;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineTemplateOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.Tier;
+import org.jclouds.abiquo.domain.network.ExternalNetwork;
+import org.jclouds.abiquo.domain.network.Network;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PrivateNetwork;
+import org.jclouds.abiquo.domain.network.PublicIp;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.predicates.infrastructure.DatacenterPredicates;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.enumerator.StatefulInclusion;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+import com.abiquo.server.core.infrastructure.storage.DisksManagementDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.abiquo.server.core.infrastructure.storage.VolumesManagementDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Represents a virtual datacenter.
+ * <p>
+ * Virtual datacenters expose a set of compute, storage and networking resources that can be
+ * consumed by the tenants.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource">
+ *      http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource</a>
+ */
+public class VirtualDatacenter extends DomainWithLimitsWrapper<VirtualDatacenterDto>
+{
+    /** The enterprise where the rack belongs. */
+    private Enterprise enterprise;
+
+    /** The dataceter where the virtual datacenter will be deployed. */
+    private Datacenter datacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected VirtualDatacenter(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VirtualDatacenterDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Delete the virtual datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-DeleteanexistingVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-DeleteanexistingVirtualDatacenter</a>
+     */
+    public void delete()
+    {
+        context.getApi().getCloudApi().deleteVirtualDatacenter(target);
+        target = null;
+    }
+
+    /**
+     * Creates the virtual datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-CreateanewVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-CreateanewVirtualDatacenter</a>
+     */
+    public void save()
+    {
+        target =
+            context.getApi().getCloudApi()
+                .createVirtualDatacenter(target, datacenter.unwrap(), enterprise.unwrap());
+    }
+
+    /**
+     * Updates the virtual datacenter information when some of its properties have changed.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-UpdatesanexistingVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-UpdatesanexistingVirtualDatacenter</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getCloudApi().updateVirtualDatacenter(target);
+    }
+
+    // Parent access
+
+    /**
+     * Gets the datacenter where this virtual datacenter is assigned.
+     * 
+     * @return The datacenter where this virtual datacenter is assigned.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Datacenter+Resource#DatacenterResource-RetrieveaDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Datacenter+Resource#DatacenterResource-
+     *      RetrieveaDatacenter</a>
+     */
+    public Datacenter getDatacenter()
+    {
+        Integer datacenterId = target.getIdFromLink(ParentLinkName.DATACENTER);
+        datacenter = getEnterprise().findAllowedDatacenter(DatacenterPredicates.id(datacenterId));
+        return datacenter;
+    }
+
+    /**
+     * Gets the enterprise that owns this virtual datacenter.
+     * 
+     * @return The enterprise that owns this virtual datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-RetrieveanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-
+     *      RetrieveanEnterprise</a>
+     */
+    public Enterprise getEnterprise()
+    {
+        Integer enterpriseId = target.getIdFromLink(ParentLinkName.ENTERPRISE);
+        enterprise =
+            wrap(context, Enterprise.class,
+                context.getApi().getEnterpriseApi().getEnterprise(enterpriseId));
+        return enterprise;
+    }
+
+    // Children access
+
+    /**
+     * Lists all the virtual appliances in the virtual datacenter.
+     * 
+     * @return The list of virtual appliances in the virtual datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Appliance+Resource#VirtualApplianceResource-RetrievethelistofVirtualAppliances"
+     *      >http://community.abiquo.com/display/ABI20/Virtual+Appliance+Resource#
+     *      VirtualApplianceResource-RetrievethelistofVirtualAppliances</a>
+     */
+    public List<VirtualAppliance> listVirtualAppliances()
+    {
+        VirtualAppliancesDto vapps = context.getApi().getCloudApi().listVirtualAppliances(target);
+        return wrap(context, VirtualAppliance.class, vapps.getCollection());
+    }
+
+    /**
+     * Lists all the virtual appliances in the virtual datacenter that match the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The list of virtual appliances in the virtual datacenter that match the given filter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Appliance+Resource#VirtualApplianceResource-RetrievethelistofVirtualAppliances"
+     *      >http://community.abiquo.com/display/ABI20/Virtual+Appliance+Resource#
+     *      VirtualApplianceResource-RetrievethelistofVirtualAppliances</a>
+     */
+    public List<VirtualAppliance> listVirtualAppliances(final Predicate<VirtualAppliance> filter)
+    {
+        return Lists.newLinkedList(filter(listVirtualAppliances(), filter));
+    }
+
+    /**
+     * Gets the first virtual appliance in the virtual datacenter that match the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return the first virtual appliance in the virtual datacenter that match the given filter or
+     *         <code>null</code> if none is found.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Appliance+Resource#VirtualApplianceResource-RetrievethelistofVirtualAppliances"
+     *      >http://community.abiquo.com/display/ABI20/Virtual+Appliance+Resource#
+     *      VirtualApplianceResource-RetrievethelistofVirtualAppliances</a>
+     */
+    public VirtualAppliance findVirtualAppliance(final Predicate<VirtualAppliance> filter)
+    {
+        return Iterables.getFirst(filter(listVirtualAppliances(), filter), null);
+    }
+
+    /**
+     * Gets the virtual appliance with the given id in the current virtual datacenter.
+     * 
+     * @param id The id of the virtual appliance to get.
+     * @return The virtual appliance.
+     */
+    public VirtualAppliance getVirtualAppliance(final Integer id)
+    {
+        VirtualApplianceDto vapp = context.getApi().getCloudApi().getVirtualAppliance(target, id);
+        return wrap(context, VirtualAppliance.class, vapp);
+    }
+
+    /**
+     * Lists the storage tiers that are available to the virtual datacenter.
+     * 
+     * @return The list of storage tiers that are available to the virtual datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-Retrieveenabledtiers"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-Retrieveenabledtiers</a>
+     */
+    public List<Tier> listStorageTiers()
+    {
+        TiersDto tiers = context.getApi().getCloudApi().listStorageTiers(target);
+        return wrap(context, Tier.class, tiers.getCollection());
+    }
+
+    /**
+     * Lists the storage tiers that are available to the virtual datacenter and match the given
+     * filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The list of storage tiers that are available to the virtual datacenter and match the
+     *         given filter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-Retrieveenabledtiers"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-Retrieveenabledtiers</a>
+     */
+    public List<Tier> listStorageTiers(final Predicate<Tier> filter)
+    {
+        return Lists.newLinkedList(filter(listStorageTiers(), filter));
+    }
+
+    /**
+     * Finds the first the storage tier that is available to the virtual datacenter and matches the
+     * given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The first the storage tier that is available to the virtual datacenter and matches
+     *         the given filter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-Retrieveenabledtiers"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-Retrieveenabledtiers</a>
+     */
+    public Tier findStorageTier(final Predicate<Tier> filter)
+    {
+        return Iterables.getFirst(filter(listStorageTiers(), filter), null);
+    }
+
+    /**
+     * Gets the storage tier with the given id from the current virtual datacenter.
+     * 
+     * @param id The id of the storage tier.
+     * @return The sotrage tier.
+     */
+    public Tier getStorageTier(final Integer id)
+    {
+        TierDto tier = context.getApi().getCloudApi().getStorageTier(target, id);
+        return wrap(context, Tier.class, tier);
+    }
+
+    /**
+     * Lists all persistent volumes in the virtual datacenter.
+     * 
+     * @return The list of all persistent volumes in the virtual datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Volume+Resource#VolumeResource-Retrievethelistofvolumes"
+     *      > http://community.abiquo.com/display/ABI20/Volume+Resource#VolumeResource-
+     *      Retrievethelistofvolumes</a>
+     */
+    public List<Volume> listVolumes()
+    {
+        VolumesManagementDto volumes = context.getApi().getCloudApi().listVolumes(target);
+        return wrap(context, Volume.class, volumes.getCollection());
+    }
+
+    /**
+     * Lists all persistent volumes in the virtual datacenter that match the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The list of all persistent volumes in the virtual datacenter that match the given
+     *         filter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Volume+Resource#VolumeResource-Retrievethelistofvolumes"
+     *      > http://community.abiquo.com/display/ABI20/Volume+Resource#VolumeResource-
+     *      Retrievethelistofvolumes</a>
+     */
+    public List<Volume> listVolumes(final Predicate<Volume> filter)
+    {
+        return Lists.newLinkedList(filter(listVolumes(), filter));
+    }
+
+    /**
+     * Finds the first persistent volume in the virtual datacenter that matches the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The first persistent volumes in the virtual datacenter that matches the given filter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Volume+Resource#VolumeResource-Retrievethelistofvolumes"
+     *      > http://community.abiquo.com/display/ABI20/Volume+Resource#VolumeResource-
+     *      Retrievethelistofvolumes</a>
+     */
+    public Volume findVolume(final Predicate<Volume> filter)
+    {
+        return Iterables.getFirst(filter(listVolumes(), filter), null);
+    }
+
+    public Volume getVolume(final Integer id)
+    {
+        VolumeManagementDto volume = context.getApi().getCloudApi().getVolume(target, id);
+        return wrap(context, Volume.class, volume);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Hard+Disks+Resource#HardDisksResource-GetthelistofHardDisksofaVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Hard+Disks+Resource#HardDisksResource-
+     *      GetthelistofHardDisksofaVirtualDatacenter</a>
+     */
+    public List<HardDisk> listHardDisks()
+    {
+        DisksManagementDto hardDisks = context.getApi().getCloudApi().listHardDisks(target);
+        return wrap(context, HardDisk.class, hardDisks.getCollection());
+    }
+
+    public List<HardDisk> listHardDisks(final Predicate<HardDisk> filter)
+    {
+        return Lists.newLinkedList(filter(listHardDisks(), filter));
+    }
+
+    public HardDisk findHardDisk(final Predicate<HardDisk> filter)
+    {
+        return Iterables.getFirst(filter(listHardDisks(), filter), null);
+    }
+
+    public HardDisk getHardDisk(final Integer id)
+    {
+        DiskManagementDto hardDisk = context.getApi().getCloudApi().getHardDisk(target, id);
+        return wrap(context, HardDisk.class, hardDisk);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-GetdefaultVLANusedbydefaultinVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-GetdefaultVLANusedbydefaultinVirtualDatacenter</a>
+     */
+    public Network< ? > getDefaultNetwork()
+    {
+        VLANNetworkDto network = context.getApi().getCloudApi().getDefaultNetwork(target);
+        return wrap(context, network.getType() == NetworkType.INTERNAL ? PrivateNetwork.class
+            : ExternalNetwork.class, network);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource-RetrievealistofPrivateNetworks"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource
+     *      -RetrievealistofPrivateNetworks</a>
+     */
+    public List<PrivateNetwork> listPrivateNetworks()
+    {
+        VLANNetworksDto networks = context.getApi().getCloudApi().listPrivateNetworks(target);
+        return wrap(context, PrivateNetwork.class, networks.getCollection());
+    }
+
+    public List<PrivateNetwork> listPrivateNetworks(final Predicate<Network<PrivateIp>> filter)
+    {
+        return Lists.newLinkedList(filter(listPrivateNetworks(), filter));
+    }
+
+    public PrivateNetwork findPrivateNetwork(final Predicate<Network<PrivateIp>> filter)
+    {
+        return Iterables.getFirst(filter(listPrivateNetworks(), filter), null);
+    }
+
+    public PrivateNetwork getPrivateNetwork(final Integer id)
+    {
+        VLANNetworkDto network = context.getApi().getCloudApi().getPrivateNetwork(target, id);
+        return wrap(context, PrivateNetwork.class, network);
+    }
+
+    /**
+     * TODO needs to be in the wiki
+     */
+    public List<VirtualMachineTemplate> listAvailableTemplates()
+    {
+        VirtualMachineTemplatesDto templates =
+            context.getApi().getCloudApi().listAvailableTemplates(target);
+
+        return wrap(context, VirtualMachineTemplate.class, templates.getCollection());
+    }
+
+    public List<VirtualMachineTemplate> listAvailableTemplates(
+        final VirtualMachineTemplateOptions options)
+    {
+        VirtualMachineTemplatesDto templates =
+            context.getApi().getCloudApi().listAvailableTemplates(target, options);
+
+        return wrap(context, VirtualMachineTemplate.class, templates.getCollection());
+    }
+
+    public List<VirtualMachineTemplate> listAvailableTempaltes(
+        final Predicate<VirtualMachineTemplate> filter)
+    {
+        return Lists.newLinkedList(filter(listAvailableTemplates(), filter));
+    }
+
+    public VirtualMachineTemplate findAvailableTemplate(
+        final Predicate<VirtualMachineTemplate> filter)
+    {
+        return Iterables.getFirst(filter(listAvailableTemplates(), filter), null);
+    }
+
+    public VirtualMachineTemplate getAvailableTemplate(final Integer id)
+    {
+        VirtualMachineTemplatesDto templates =
+            context
+                .getApi()
+                .getCloudApi()
+                .listAvailableTemplates(target,
+                    VirtualMachineTemplateOptions.builder().idTemplate(id).build());
+
+        return templates.getCollection().isEmpty() ? null : //
+            wrap(context, VirtualMachineTemplate.class, templates.getCollection().get(0));
+    }
+
+    public VirtualMachineTemplate getAvailablePersistentTemplate(final Integer id)
+    {
+        VirtualMachineTemplatesDto templates =
+            context
+                .getApi()
+                .getCloudApi()
+                .listAvailableTemplates(
+                    target,
+                    VirtualMachineTemplateOptions.builder().idTemplate(id)
+                        .persistent(StatefulInclusion.ALL).build());
+
+        return templates.getCollection().isEmpty() ? null : //
+            wrap(context, VirtualMachineTemplate.class, templates.getCollection().get(0));
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-ListofPublicIPstopurchasebyVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-ListofPublicIPstopurchasebyVirtualDatacenter</a>
+     */
+    public List<PublicIp> listAvailablePublicIps()
+    {
+        IpOptions options = IpOptions.builder().build();
+
+        PublicIpsDto ips = context.getApi().getCloudApi().listAvailablePublicIps(target, options);
+
+        return wrap(context, PublicIp.class, ips.getCollection());
+    }
+
+    public List<PublicIp> listAvailablePublicIps(final Predicate<PublicIp> filter)
+    {
+        return Lists.newLinkedList(filter(listAvailablePublicIps(), filter));
+    }
+
+    public PublicIp findAvailablePublicIp(final Predicate<PublicIp> filter)
+    {
+        return Iterables.getFirst(filter(listAvailablePublicIps(), filter), null);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-ListofpurchasedPublicIPsbyVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-ListofpurchasedPublicIPsbyVirtualDatacenter</a>
+     */
+    public List<PublicIp> listPurchasedPublicIps()
+    {
+        IpOptions options = IpOptions.builder().build();
+
+        PublicIpsDto ips = context.getApi().getCloudApi().listPurchasedPublicIps(target, options);
+
+        return wrap(context, PublicIp.class, ips.getCollection());
+    }
+
+    public List<PublicIp> listPurchasedPublicIps(final Predicate<PublicIp> filter)
+    {
+        return Lists.newLinkedList(filter(listPurchasedPublicIps(), filter));
+    }
+
+    public PublicIp findPurchasedPublicIp(final Predicate<PublicIp> filter)
+    {
+        return Iterables.getFirst(filter(listPurchasedPublicIps(), filter), null);
+    }
+
+    public void purchasePublicIp(final PublicIp ip)
+    {
+        checkNotNull(ip.unwrap().searchLink("purchase"), ValidationErrors.MISSING_REQUIRED_LINK);
+        context.getApi().getCloudApi().purchasePublicIp(ip.unwrap());
+    }
+
+    public void releaseePublicIp(final PublicIp ip)
+    {
+        checkNotNull(ip.unwrap().searchLink("release"), ValidationErrors.MISSING_REQUIRED_LINK);
+        context.getApi().getCloudApi().releasePublicIp(ip.unwrap());
+    }
+
+    // Actions
+
+    public void setDefaultNetwork(final Network< ? > network)
+    {
+        context.getApi().getCloudApi().setDefaultNetwork(target, network.unwrap());
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Datacenter datacenter, final Enterprise enterprise)
+    {
+        return new Builder(context, datacenter, enterprise);
+    }
+
+    public static class Builder extends LimitsBuilder<Builder>
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name;
+
+        private HypervisorType hypervisorType;
+
+        private Enterprise enterprise;
+
+        private Datacenter datacenter;
+
+        private PrivateNetwork network;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Datacenter datacenter, final Enterprise enterprise)
+        {
+            super();
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            checkNotNull(enterprise, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+            this.enterprise = enterprise;
+            this.context = context;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder hypervisorType(final HypervisorType hypervisorType)
+        {
+            this.hypervisorType = hypervisorType;
+            return this;
+        }
+
+        public Builder datacenter(final Datacenter datacenter)
+        {
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            return this;
+        }
+
+        public Builder enterprise(final Enterprise enterprise)
+        {
+            checkNotNull(enterprise, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+            this.enterprise = enterprise;
+            return this;
+        }
+
+        public Builder network(final PrivateNetwork network)
+        {
+            checkNotNull(network, ValidationErrors.NULL_RESOURCE + PrivateNetwork.class);
+            this.network = network;
+            return this;
+        }
+
+        public VirtualDatacenter build()
+        {
+            VirtualDatacenterDto dto = new VirtualDatacenterDto();
+            dto.setName(name);
+            dto.setRamLimitsInMb(ramSoftLimitInMb, ramHardLimitInMb);
+            dto.setCpuCountLimits(cpuCountSoftLimit, cpuCountHardLimit);
+            dto.setHdLimitsInMb(hdSoftLimitInMb, hdHardLimitInMb);
+            dto.setStorageLimits(storageSoft, storageHard);
+            dto.setVlansLimits(vlansSoft, vlansHard);
+            dto.setPublicIPLimits(publicIpsSoft, publicIpsHard);
+            dto.setName(name);
+            dto.setHypervisorType(hypervisorType);
+            dto.setVlan(network.unwrap());
+
+            VirtualDatacenter virtualDatacenter = new VirtualDatacenter(context, dto);
+            virtualDatacenter.datacenter = datacenter;
+            virtualDatacenter.enterprise = enterprise;
+
+            return virtualDatacenter;
+        }
+
+        public static Builder fromVirtualDatacenter(final VirtualDatacenter in)
+        {
+            return VirtualDatacenter.builder(in.context, in.datacenter, in.enterprise)
+                .name(in.getName()).ramLimits(in.getRamSoftLimitInMb(), in.getRamHardLimitInMb())
+                .cpuCountLimits(in.getCpuCountSoftLimit(), in.getCpuCountHardLimit())
+                .hdLimitsInMb(in.getHdSoftLimitInMb(), in.getHdHardLimitInMb())
+                .storageLimits(in.getStorageSoft(), in.getStorageHard())
+                .vlansLimits(in.getVlansSoft(), in.getVlansHard())
+                .publicIpsLimits(in.getPublicIpsSoft(), in.getPublicIpsHard())
+                .hypervisorType(in.getHypervisorType());
+        }
+    }
+
+    // Delegate methods
+
+    public HypervisorType getHypervisorType()
+    {
+        return target.getHypervisorType();
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public void setHypervisorType(final HypervisorType hypervisorType)
+    {
+        target.setHypervisorType(hypervisorType);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "VirtualDatacenter [id=" + getId() + ", type=" + getHypervisorType() + ", name="
+            + getName() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachine.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachine.java
new file mode 100644
index 0000000..e45d817
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachine.java
@@ -0,0 +1,1014 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.DomainWithTasksWrapper;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.Network;
+import org.jclouds.abiquo.domain.network.UnmanagedNetwork;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.domain.util.LinkUtils;
+import org.jclouds.abiquo.predicates.LinkPredicates;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.abiquo.strategy.cloud.ListAttachedNics;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.abiquo.server.core.cloud.VirtualMachineStateDto;
+import com.abiquo.server.core.cloud.VirtualMachineTaskDto;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpDto;
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+import com.abiquo.server.core.infrastructure.storage.DisksManagementDto;
+import com.abiquo.server.core.infrastructure.storage.DvdManagementDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.abiquo.server.core.infrastructure.storage.VolumesManagementDto;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to {@link VirtualMachineWithNodeExtendedDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/VirtualMachineResource">
+ *      http://community.abiquo.com/display/ABI20/VirtualMachineResource</a>
+ */
+public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNodeExtendedDto>
+{
+    /** The virtual appliance where the virtual machine belongs. */
+    private VirtualAppliance virtualAppliance;
+
+    /** The virtual machine template of the virtual machine. */
+    private VirtualMachineTemplate template;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected VirtualMachine(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VirtualMachineWithNodeExtendedDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Delete the virtual machine.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineResource#VirtualMachineResource-Deleteavirtualmachine"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/VirtualMachineResource#VirtualMachineResource
+     *      -Deleteavirtualmachine</a>
+     */
+    public void delete()
+    {
+        context.getApi().getCloudApi().deleteVirtualMachine(target);
+        target = null;
+    }
+
+    /**
+     * Create a new virtual machine in Abiquo.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineResource#VirtualMachineResource-Createavirtualmachine"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineResource#
+     *      VirtualMachineResource-Createavirtualmachine</a>
+     */
+    public void save()
+    {
+        checkNotNull(template, ValidationErrors.NULL_RESOURCE + VirtualMachineTemplate.class);
+        checkNotNull(template.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in "
+            + VirtualMachineTemplate.class);
+
+        this.updateLink(target, ParentLinkName.VIRTUAL_MACHINE_TEMPLATE, template.unwrap(), "edit");
+
+        target =
+            context.getApi().getCloudApi().createVirtualMachine(virtualAppliance.unwrap(), target);
+    }
+
+    /**
+     * Update virtual machine information in the server with the data from this virtual machine.
+     * This is an asynchronous call. This method returns a
+     * {@link org.jclouds.abiquo.domain.task.AsyncTask} object that keeps track of the task
+     * completion. Please refer to the documentation for details.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineResource#VirtualMachineResource-Modifyavirtualmachine"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineResource#
+     *      VirtualMachineResource-Modifyavirtualmachine</a>
+     * @see github: <a href=
+     *      "https://github.com/abiquo/jclouds-abiquo/wiki/Asynchronous-monitor-example" >
+     *      https://github.com/abiquo/jclouds-abiquo/wiki/Asynchronous-monitor-example</a>
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    public AsyncTask update()
+    {
+        AcceptedRequestDto<String> taskRef =
+            context.getApi().getCloudApi().updateVirtualMachine(target);
+        return taskRef == null ? null : getTask(taskRef);
+    }
+
+    /**
+     * Update virtual machine information in the server with the data from this virtual machine.
+     * This is an asynchronous call. This method returns a
+     * {@link org.jclouds.abiquo.domain.task.AsyncTask} object that keeps track of the task
+     * completion. Please refer to the documentation for details.
+     * 
+     * @param force Force update.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineResource#VirtualMachineResource-Modifyavirtualmachine"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineResource#
+     *      VirtualMachineResource-Modifyavirtualmachine</a>
+     * @see github: <a href=
+     *      "https://github.com/abiquo/jclouds-abiquo/wiki/Asynchronous-monitor-example" >
+     *      https://github.com/abiquo/jclouds-abiquo/wiki/Asynchronous-monitor-example</a>
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    public AsyncTask update(final boolean force)
+    {
+        AcceptedRequestDto<String> taskRef =
+            context.getApi().getCloudApi()
+                .updateVirtualMachine(target, VirtualMachineOptions.builder().force(force).build());
+        return taskRef == null ? null : getTask(taskRef);
+    }
+
+    /**
+     * Change the state of the virtual machine. This is an asynchronous call. This method returns a
+     * {@link org.jclouds.abiquo.domain.task.AsyncTask} object that keeps track of the task
+     * completion. Please refer to the documentation for details.
+     * 
+     * @param state The new state of the virtual machine.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineResource#VirtualMachineResource-Changethestateofavirtualmachine"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineResource#
+     *      VirtualMachineResource-Changethestateofavirtualmachine</a>
+     * @see github: <a href=
+     *      "https://github.com/abiquo/jclouds-abiquo/wiki/Asynchronous-monitor-example" >
+     *      https://github.com/abiquo/jclouds-abiquo/wiki/Asynchronous-monitor-example</a>
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    public AsyncTask changeState(final VirtualMachineState state)
+    {
+        VirtualMachineStateDto dto = new VirtualMachineStateDto();
+        dto.setState(state);
+
+        AcceptedRequestDto<String> taskRef =
+            context.getApi().getCloudApi().changeVirtualMachineState(target, dto);
+
+        return getTask(taskRef);
+    }
+
+    /**
+     * Retrieve the state of the virtual machine.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineResource#VirtualMachineResource-Retrievethestateofthevirtualmachine"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineResource#
+     *      VirtualMachineResource-Retrievethestateofthevirtualmachine</a>
+     * @return Current state of the virtual machine.
+     */
+    public VirtualMachineState getState()
+    {
+        VirtualMachineStateDto stateDto =
+            context.getApi().getCloudApi().getVirtualMachineState(target);
+        VirtualMachineState state = stateDto.getState();
+        target.setState(state);
+        target.setIdState(state.id());
+        return state;
+    }
+
+    public void refresh()
+    {
+        RESTLink link =
+            checkNotNull(target.getEditLink(), ValidationErrors.MISSING_REQUIRED_LINK + " edit");
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<VirtualMachineWithNodeExtendedDto> parser =
+            new ParseXMLWithJAXB<VirtualMachineWithNodeExtendedDto>(utils.getXml(),
+                TypeLiteral.get(VirtualMachineWithNodeExtendedDto.class));
+
+        target = parser.apply(response);
+    }
+
+    // Parent access
+
+    /**
+     * Retrieve the virtual appliance where this virtual machine is.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualApplianceResource#VirtualApplianceResource-Retrieveavirtualappliance"
+     *      > http://community.abiquo.com/display/ABI20/VirtualApplianceResource#
+     *      VirtualApplianceResource-Retrieveavirtualappliance</a>
+     * @return The virtual appliance where this virtual machine is.
+     */
+    public VirtualAppliance getVirtualAppliance()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.VIRTUAL_APPLIANCE),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.VIRTUAL_APPLIANCE);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<VirtualApplianceDto> parser =
+            new ParseXMLWithJAXB<VirtualApplianceDto>(utils.getXml(),
+                TypeLiteral.get(VirtualApplianceDto.class));
+
+        return wrap(context, VirtualAppliance.class, parser.apply(response));
+    }
+
+    /**
+     * Retrieve the virtual datacenter where this virtual machine is.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualDatacenterResource#VirtualDatacenterResource-Retireveavirtualdatacenter"
+     *      > http://community.abiquo.com/display/ABI20/VirtualDatacenterResource#
+     *      VirtualDatacenterResource-Retireveavirtualdatacenter</a>
+     * @return The virtual datacenter where this virtual machine is.
+     */
+    public VirtualDatacenter getVirtualDatacenter()
+    {
+        Integer virtualDatacenterId = target.getIdFromLink(ParentLinkName.VIRTUAL_DATACENTER);
+        VirtualDatacenterDto dto =
+            context.getApi().getCloudApi().getVirtualDatacenter(virtualDatacenterId);
+        return wrap(context, VirtualDatacenter.class, dto);
+    }
+
+    /**
+     * Retrieve the enterprise of this virtual machine.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrieveanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrieveanEnterprise</a>
+     * @return Enterprise of this virtual machine.
+     */
+    public Enterprise getEnterprise()
+    {
+        Integer enterpriseId = target.getIdFromLink(ParentLinkName.ENTERPRISE);
+        EnterpriseDto dto = context.getApi().getEnterpriseApi().getEnterprise(enterpriseId);
+        return wrap(context, Enterprise.class, dto);
+    }
+
+    /**
+     * Retrieve the template of this virtual machine.
+     * 
+     * @return Template of this virtual machine.
+     */
+    public VirtualMachineTemplate getTemplate()
+    {
+        VirtualMachineTemplateDto dto =
+            context.getApi().getCloudApi().getVirtualMachineTemplate(target);
+        return wrap(context, VirtualMachineTemplate.class, dto);
+    }
+
+    // Children access
+
+    public List<HardDisk> listAttachedHardDisks()
+    {
+        refresh();
+        DisksManagementDto hardDisks = context.getApi().getCloudApi().listAttachedHardDisks(target);
+        return wrap(context, HardDisk.class, hardDisks.getCollection());
+    }
+
+    public List<HardDisk> listAttachedHardDisks(final Predicate<HardDisk> filter)
+    {
+        return Lists.newLinkedList(filter(listAttachedHardDisks(), filter));
+    }
+
+    public HardDisk findAttachedHardDisk(final Predicate<HardDisk> filter)
+    {
+        return Iterables.getFirst(filter(listAttachedHardDisks(), filter), null);
+    }
+
+    public List<Volume> listAttachedVolumes()
+    {
+        refresh();
+        VolumesManagementDto volumes = context.getApi().getCloudApi().listAttachedVolumes(target);
+        return wrap(context, Volume.class, volumes.getCollection());
+    }
+
+    public List<Volume> listAttachedVolumes(final Predicate<Volume> filter)
+    {
+        return Lists.newLinkedList(filter(listAttachedVolumes(), filter));
+    }
+
+    public Volume findAttachedVolume(final Predicate<Volume> filter)
+    {
+        return Iterables.getFirst(filter(listAttachedVolumes(), filter), null);
+    }
+
+    public List<Ip< ? , ? >> listAttachedNics()
+    {
+        // The strategy will refresh the vm. There is no need to do it here
+        ListAttachedNics strategy =
+            context.getUtils().getInjector().getInstance(ListAttachedNics.class);
+        return Lists.newLinkedList(strategy.execute(this));
+    }
+
+    public List<Ip< ? , ? >> listAttachedNics(final Predicate<Ip< ? , ? >> filter)
+    {
+        return Lists.newLinkedList(filter(listAttachedNics(), filter));
+    }
+
+    public Ip< ? , ? > findAttachedNic(final Predicate<Ip< ? , ? >> filter)
+    {
+        return Iterables.getFirst(filter(listAttachedNics(), filter), null);
+    }
+
+    // Actions
+
+    public AsyncTask deploy()
+    {
+        return deploy(false);
+    }
+
+    public AsyncTask deploy(final boolean forceEnterpriseSoftLimits)
+    {
+        VirtualMachineTaskDto force = new VirtualMachineTaskDto();
+        force.setForceEnterpriseSoftLimits(forceEnterpriseSoftLimits);
+
+        AcceptedRequestDto<String> response =
+            context.getApi().getCloudApi().deployVirtualMachine(unwrap(), force);
+
+        return getTask(response);
+    }
+
+    public AsyncTask undeploy()
+    {
+        return undeploy(false);
+    }
+
+    public AsyncTask undeploy(final boolean forceUndeploy)
+    {
+        VirtualMachineTaskDto force = new VirtualMachineTaskDto();
+        force.setForceUndeploy(forceUndeploy);
+
+        AcceptedRequestDto<String> response =
+            context.getApi().getCloudApi().undeployVirtualMachine(unwrap(), force);
+
+        return getTask(response);
+    }
+
+    /**
+     * Reboot a virtual machine. This is an asynchronous call. This method returns a
+     * {@link org.jclouds.abiquo.domain.task.AsyncTask} object that keeps track of the task
+     * completion. Please refer to the documentation for details.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineResource#VirtualMachineResource-Resetavirtualmachine"
+     *      > http://community.abiquo.com/display/ABI20/Rack+Resource#/VirtualMachineResource#
+     *      VirtualMachineResource-Resetavirtualmachine</a>
+     * @see github: <a href=
+     *      "https://github.com/abiquo/jclouds-abiquo/wiki/Asynchronous-monitor-example" >
+     *      https://github.com/abiquo/jclouds-abiquo/wiki/Asynchronous-monitor-example</a>
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    public AsyncTask reboot()
+    {
+        AcceptedRequestDto<String> response =
+            context.getApi().getCloudApi().rebootVirtualMachine(unwrap());
+
+        return getTask(response);
+    }
+
+    public AsyncTask attachHardDisks(final HardDisk... hardDisks)
+    {
+        List<HardDisk> expected = listAttachedHardDisks();
+        expected.addAll(Arrays.asList(hardDisks));
+
+        HardDisk[] disks = new HardDisk[expected.size()];
+        return setHardDisks(expected.toArray(disks));
+    }
+
+    public AsyncTask detachAllHardDisks()
+    {
+        AcceptedRequestDto<String> taskRef =
+            context.getApi().getCloudApi().detachAllHardDisks(target);
+        return taskRef == null ? null : getTask(taskRef);
+    }
+
+    public AsyncTask detachHardDisks(final HardDisk... hardDisks)
+    {
+        List<HardDisk> expected = listAttachedHardDisks();
+        Iterables.removeIf(expected, hardDiskIdIn(hardDisks));
+
+        HardDisk[] disks = new HardDisk[expected.size()];
+        return setHardDisks(expected.toArray(disks));
+    }
+
+    public AsyncTask setHardDisks(final HardDisk... hardDisks)
+    {
+        AcceptedRequestDto<String> taskRef =
+            context.getApi().getCloudApi().replaceHardDisks(target, toHardDiskDto(hardDisks));
+        return taskRef == null ? null : getTask(taskRef);
+    }
+
+    public AsyncTask attachVolumes(final Volume... volumes)
+    {
+        List<Volume> expected = listAttachedVolumes();
+        expected.addAll(Arrays.asList(volumes));
+
+        Volume[] vols = new Volume[expected.size()];
+        return setVolumes(true, expected.toArray(vols));
+    }
+
+    public AsyncTask detachAllVolumes()
+    {
+        AcceptedRequestDto<String> taskRef =
+            context.getApi().getCloudApi().detachAllVolumes(target);
+        return taskRef == null ? null : getTask(taskRef);
+    }
+
+    public AsyncTask detachVolumes(final Volume... volumes)
+    {
+        List<Volume> expected = listAttachedVolumes();
+        Iterables.removeIf(expected, volumeIdIn(volumes));
+
+        Volume[] vols = new Volume[expected.size()];
+        return setVolumes(true, expected.toArray(vols));
+    }
+
+    public AsyncTask setVolumes(final Boolean forceSoftLimits, final Volume... volumes)
+    {
+        AcceptedRequestDto<String> taskRef =
+            context
+                .getApi()
+                .getCloudApi()
+                .replaceVolumes(target,
+                    VirtualMachineOptions.builder().force(forceSoftLimits).build(),
+                    toVolumeDto(volumes));
+
+        return taskRef == null ? null : getTask(taskRef);
+    }
+
+    public AsyncTask setVolumes(final Volume... volumes)
+    {
+        return setVolumes(true, volumes);
+    }
+
+    public AsyncTask setNics(final List<Ip< ? , ? >> ips)
+    {
+        // By default the network of the first ip will be used as a gateway
+        return setNics(ips != null && !ips.isEmpty() ? ips.get(0).getNetwork() : null, ips, null);
+    }
+
+    public AsyncTask setNics(final List<Ip< ? , ? >> ips,
+        final List<UnmanagedNetwork> unmanagetNetworks)
+    {
+        // By default the network of the first ip will be used as a gateway
+        Network< ? > gateway = null;
+        if (ips != null && !ips.isEmpty())
+        {
+            gateway = ips.get(0).getNetwork();
+        }
+        else if (unmanagetNetworks != null && !unmanagetNetworks.isEmpty())
+        {
+            gateway = unmanagetNetworks.get(0);
+        }
+
+        return setNics(gateway, ips, unmanagetNetworks);
+    }
+
+    public AsyncTask setNics(final Network< ? > gatewayNetwork, final List<Ip< ? , ? >> ips)
+    {
+        return setNics(gatewayNetwork, ips, null);
+    }
+
+    public AsyncTask setNics(final Network< ? > gatewayNetwork, final List<Ip< ? , ? >> ips,
+        final List<UnmanagedNetwork> unmanagetNetworks)
+    {
+        RESTLink configLink =
+            checkNotNull(target.searchLink(ParentLinkName.NETWORK_CONFIGURATIONS),
+                ValidationErrors.MISSING_REQUIRED_LINK + ParentLinkName.NETWORK_CONFIGURATIONS);
+
+        // Remove the gateway configuration and the current nics
+        Iterables.removeIf(
+            target.getLinks(),
+            Predicates.or(LinkPredicates.isNic(),
+                LinkPredicates.rel(ParentLinkName.NETWORK_GATEWAY)));
+
+        // Add the given nics in the appropriate order
+        int i = 0;
+        if (ips != null)
+        {
+            for (i = 0; i < ips.size(); i++)
+            {
+                RESTLink source = LinkUtils.getSelfLink(ips.get(i).unwrap());
+                RESTLink link = new RESTLink("nic" + i, source.getHref());
+                link.setType(ips.get(i).unwrap().getBaseMediaType());
+                target.addLink(link);
+            }
+        }
+
+        // Add unmanaged network references, if given
+        if (unmanagetNetworks != null)
+        {
+            for (UnmanagedNetwork unmanaged : unmanagetNetworks)
+            {
+                RESTLink source =
+                    checkNotNull(unmanaged.unwrap().searchLink("ips"),
+                        ValidationErrors.MISSING_REQUIRED_LINK + "ips");
+
+                RESTLink link = new RESTLink("nic" + i, source.getHref());
+                link.setType(UnmanagedIpDto.BASE_MEDIA_TYPE);
+                target.addLink(link);
+                i++;
+            }
+        }
+
+        // Set the new network configuration
+        if (gatewayNetwork != null)
+        {
+            target.addLink(new RESTLink(ParentLinkName.NETWORK_GATEWAY, configLink.getHref() + "/"
+                + gatewayNetwork.getId()));
+        }
+
+        return update(true);
+    }
+
+    // TODO: Get current gateway network
+
+    public void setGatewayNetwork(final Network< ? > network)
+    {
+        context.getApi().getCloudApi().setGatewayNetwork(target, network.unwrap());
+        refresh(); // First refresh the target and its links
+    }
+
+    /**
+     * Checks if the virtual machine is persistent.
+     * <p>
+     * Persistent virtual machines have the system disc in an external volume. This way, when the
+     * virtual machine is undeployed, the contents of the system disk remain in the storage device
+     * and the user can deploy the virtual machine again without losing the data in the system disk.
+     * 
+     * @return Boolean indicating if the virtual machine is persistent.
+     */
+    public boolean isPersistent()
+    {
+        return getTemplate().unwrap().searchLink("volume") != null;
+    }
+
+    public boolean hasDvd()
+    {
+        return target.getDvd() != null;
+    }
+
+    public void attachDvd()
+    {
+        DvdManagementDto dvd = new DvdManagementDto();
+        RESTLink link = new RESTLink("image", "");
+        dvd.addLink(link);
+        target.setDvd(dvd);
+    }
+
+    public void detachDvd()
+    {
+        target.setDvd(null);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VirtualAppliance virtualAppliance, final VirtualMachineTemplate template)
+    {
+        return new Builder(context, virtualAppliance, template);
+    }
+
+    public static class Builder
+    {
+        private final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private VirtualAppliance virtualAppliance;
+
+        private final VirtualMachineTemplate template;
+
+        private String nameLabel;
+
+        private String internalName;
+
+        private String description;
+
+        private Integer ram;
+
+        private Integer cpu;
+
+        private Integer vncPort;
+
+        private String vncAddress;
+
+        private Integer idState;
+
+        private Integer idType;
+
+        private String password;
+
+        private String keymap;
+
+        private String uuid;
+
+        private boolean dvd;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final VirtualAppliance virtualAppliance, final VirtualMachineTemplate template)
+        {
+            super();
+            checkNotNull(virtualAppliance, ValidationErrors.NULL_RESOURCE + VirtualAppliance.class);
+            this.virtualAppliance = virtualAppliance;
+            this.template = template;
+            this.context = context;
+        }
+
+        public Builder nameLabel(final String nameLabel)
+        {
+            this.nameLabel = nameLabel;
+            return this;
+        }
+
+        public Builder description(final String description)
+        {
+            this.description = description;
+            return this;
+        }
+
+        public Builder ram(final int ram)
+        {
+            this.ram = ram;
+            return this;
+        }
+
+        public Builder cpu(final int cpu)
+        {
+            this.cpu = cpu;
+            return this;
+        }
+
+        public Builder password(final String password)
+        {
+            this.password = password;
+            return this;
+        }
+
+        public Builder keymap(final String keymap)
+        {
+            this.keymap = keymap;
+            return this;
+        }
+
+        public Builder dvd(final boolean dvd)
+        {
+            this.dvd = dvd;
+            return this;
+        }
+
+        // This methods are used only to build a builder from an existing VirtualMachine but should
+        // never be used by the user. This fields are set automatically by Abiquo
+
+        private Builder vncPort(final int vdrpPort)
+        {
+            this.vncPort = vdrpPort;
+            return this;
+        }
+
+        private Builder vncAddress(final String vdrpIP)
+        {
+            this.vncAddress = vdrpIP;
+            return this;
+        }
+
+        private Builder idState(final int idState)
+        {
+            this.idState = idState;
+            return this;
+        }
+
+        private Builder idType(final int idType)
+        {
+            this.idType = idType;
+            return this;
+        }
+
+        private Builder internalName(final String internalName)
+        {
+            this.internalName = internalName;
+            return this;
+        }
+
+        public Builder virtualAppliance(final VirtualAppliance virtualAppliance)
+        {
+            checkNotNull(virtualAppliance, ValidationErrors.NULL_RESOURCE + VirtualAppliance.class);
+            this.virtualAppliance = virtualAppliance;
+            return this;
+        }
+
+        public VirtualMachine build()
+        {
+            VirtualMachineWithNodeExtendedDto dto = new VirtualMachineWithNodeExtendedDto();
+            dto.setNodeName(nameLabel);
+            dto.setDescription(description);
+            dto.setHdInBytes(template.getHdRequired());
+            dto.setVdrpIP(vncAddress);
+
+            if (cpu != null)
+            {
+                dto.setCpu(cpu);
+            }
+
+            if (ram != null)
+            {
+                dto.setRam(ram);
+            }
+
+            if (vncPort != null)
+            {
+                dto.setVdrpPort(vncPort);
+            }
+
+            if (idState != null)
+            {
+                dto.setIdState(idState);
+            }
+
+            if (idType != null)
+            {
+                dto.setIdType(idType);
+            }
+
+            if (internalName != null)
+            {
+                dto.setName(internalName);
+            }
+
+            dto.setPassword(password);
+            dto.setKeymap(keymap);
+            dto.setUuid(uuid);
+
+            // DVD
+            if (dvd)
+            {
+                DvdManagementDto dvd = new DvdManagementDto();
+                RESTLink link = new RESTLink("image", "");
+                dvd.addLink(link);
+                dto.setDvd(dvd);
+            }
+
+            VirtualMachine virtualMachine = new VirtualMachine(context, dto);
+            virtualMachine.virtualAppliance = virtualAppliance;
+            virtualMachine.template = template;
+
+            return virtualMachine;
+        }
+
+        public static Builder fromVirtualMachine(final VirtualMachine in)
+        {
+            return VirtualMachine.builder(in.context, in.virtualAppliance, in.template)
+                .internalName(in.getInternalName()).nameLabel(in.getNameLabel())
+                .description(in.getDescription()).ram(in.getRam()).cpu(in.getCpu())
+                .vncAddress(in.getVncAddress()).vncPort(in.getVncPort()).idState(in.getIdState())
+                .idType(in.getIdType()).password(in.getPassword()).keymap(in.getKeymap())
+                .dvd(in.hasDvd());
+        }
+    }
+
+    // Delegate methods
+
+    public int getCpu()
+    {
+        return target.getCpu();
+    }
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    // Read-only field. This value is computed from the size of the Template
+    public long getHdInBytes()
+    {
+        return target.getHdInBytes();
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public int getIdState()
+    {
+        return target.getIdState();
+    }
+
+    public int getIdType()
+    {
+        return target.getIdType();
+    }
+
+    public String getNameLabel()
+    {
+        return target.getNodeName();
+    }
+
+    public String getOwnerName()
+    {
+        return target.getUserName() + " " + target.getUserSurname();
+    }
+
+    public String getInternalName()
+    {
+        return target.getName();
+    }
+
+    public String getPassword()
+    {
+        return target.getPassword();
+    }
+
+    public int getRam()
+    {
+        return target.getRam();
+    }
+
+    public String getUuid()
+    {
+        return target.getUuid();
+    }
+
+    public String getVncAddress()
+    {
+        return target.getVdrpIP();
+    }
+
+    public int getVncPort()
+    {
+        return target.getVdrpPort();
+    }
+
+    public String getKeymap()
+    {
+        return target.getKeymap();
+    }
+
+    public void setCpu(final int cpu)
+    {
+        target.setCpu(cpu);
+    }
+
+    public void setDescription(final String description)
+    {
+        target.setDescription(description);
+    }
+
+    public void setNameLabel(final String nameLabel)
+    {
+        target.setNodeName(nameLabel);
+    }
+
+    public void setPassword(final String password)
+    {
+        target.setPassword(password);
+    }
+
+    public void setRam(final int ram)
+    {
+        target.setRam(ram);
+    }
+
+    public void setKeymap(final String keymap)
+    {
+        target.setKeymap(keymap);
+    }
+
+    private static VolumeManagementDto[] toVolumeDto(final Volume... volumes)
+    {
+        checkNotNull(volumes, "must provide at least one volume");
+
+        VolumeManagementDto[] dtos = new VolumeManagementDto[volumes.length];
+        for (int i = 0; i < volumes.length; i++)
+        {
+            dtos[i] = volumes[i].unwrap();
+        }
+
+        return dtos;
+    }
+
+    private static DiskManagementDto[] toHardDiskDto(final HardDisk... hardDisks)
+    {
+        checkNotNull(hardDisks, "must provide at least one hard disk");
+
+        DiskManagementDto[] dtos = new DiskManagementDto[hardDisks.length];
+        for (int i = 0; i < hardDisks.length; i++)
+        {
+            dtos[i] = hardDisks[i].unwrap();
+        }
+
+        return dtos;
+    }
+
+    private static Predicate<Volume> volumeIdIn(final Volume... volumes)
+    {
+        return new Predicate<Volume>()
+        {
+            List<Integer> ids = volumeIds(Arrays.asList(volumes));
+
+            @Override
+            public boolean apply(final Volume input)
+            {
+                return ids.contains(input.getId());
+            }
+        };
+    }
+
+    private static Predicate<HardDisk> hardDiskIdIn(final HardDisk... hardDisks)
+    {
+        return new Predicate<HardDisk>()
+        {
+            List<Integer> ids = hardDisksIds(Arrays.asList(hardDisks));
+
+            @Override
+            public boolean apply(final HardDisk input)
+            {
+                return ids.contains(input.getId());
+            }
+        };
+    }
+
+    private static List<Integer> volumeIds(final List<Volume> volumes)
+    {
+        return Lists.transform(volumes, new Function<Volume, Integer>()
+        {
+            @Override
+            public Integer apply(final Volume input)
+            {
+                return input.getId();
+            }
+        });
+    }
+
+    private static List<Integer> hardDisksIds(final List<HardDisk> HardDisk)
+    {
+        return Lists.transform(HardDisk, new Function<HardDisk, Integer>()
+        {
+            @Override
+            public Integer apply(final HardDisk input)
+            {
+                return input.getId();
+            }
+        });
+    }
+
+    @Override
+    public String toString()
+    {
+        return "VirtualMachine [id=" + getId() + ", state=" + target.getState().name() + ", cpu="
+            + getCpu() + ", description=" + getDescription() + ", hdInBytes=" + getHdInBytes()
+            + ", idType=" + getIdType() + ", nameLabel=" + getNameLabel() + ", internalName="
+            + getInternalName() + ", password=" + getPassword() + ", ram=" + getRam() + ", uuid="
+            + getUuid() + ", vncAddress=" + getVncAddress() + ", vncPort=" + getVncPort()
+            + ", keymap=" + getKeymap() + ", dvd=" + hasDvd() + "]";
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplate.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplate.java
new file mode 100644
index 0000000..d7df2d7
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplate.java
@@ -0,0 +1,407 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.cloud.options.ConversionOptions;
+import org.jclouds.abiquo.domain.config.Category;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.Tier;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.ConversionState;
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.appslibrary.CategoryDto;
+import com.abiquo.server.core.appslibrary.ConversionDto;
+import com.abiquo.server.core.appslibrary.ConversionsDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatePersistentDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to {@link VirtualMachineTemplateDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Virtual+Machine+Template+Resource">
+ *      http://community.abiquo.com/display/ABI20/Virtual+Machine+Template+Resource</a>
+ */
+public class VirtualMachineTemplate extends DomainWrapper<VirtualMachineTemplateDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected VirtualMachineTemplate(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VirtualMachineTemplateDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    public void delete()
+    {
+        context.getApi().getVirtualMachineTemplateApi().deleteVirtualMachineTemplate(target);
+        target = null;
+    }
+
+    public void update()
+    {
+        target =
+            context.getApi().getVirtualMachineTemplateApi().updateVirtualMachineTemplate(target);
+    }
+
+    /**
+     * TODO
+     * 
+     * @param vdc
+     * @param volume
+     * @param persistentTemplateName
+     * @param persistentVolumeName
+     * @return
+     */
+    public AsyncTask makePersistent(final VirtualDatacenter vdc, final Volume volume,
+        final String persistentTemplateName)
+    {
+        RESTLink storageLink = volume.unwrap().getEditLink();
+        storageLink.setRel("volume");
+        return makePeristent(vdc, storageLink, persistentTemplateName, null);
+    }
+
+    public AsyncTask makePersistent(final VirtualDatacenter vdc, final Tier tier,
+        final String persistentTemplateName, final String persistentVolumeName)
+    {
+        // infrastructure
+        RESTLink storageLink = tier.unwrap().getEditLink();
+        if (storageLink == null)
+        {
+            // cloud
+            storageLink = tier.unwrap().searchLink("self");
+        }
+        storageLink.setRel(ParentLinkName.TIER);
+        return makePeristent(vdc, storageLink, persistentTemplateName, persistentVolumeName);
+    }
+
+    private AsyncTask makePeristent(final VirtualDatacenter vdc, final RESTLink storageLink,
+        final String persistentTemplateName, final String persistentVolumeName)
+    {
+        VirtualMachineTemplatePersistentDto persistentData =
+            new VirtualMachineTemplatePersistentDto();
+        persistentData.setPersistentTemplateName(persistentTemplateName);
+        persistentData.setPersistentVolumeName(persistentVolumeName);
+        RESTLink vdcLink =
+            new RESTLink(ParentLinkName.VIRTUAL_DATACENTER, vdc.unwrap().getEditLink().getHref());
+        RESTLink templateLink =
+            new RESTLink(ParentLinkName.VIRTUAL_MACHINE_TEMPLATE, target.getEditLink().getHref());
+
+        persistentData.addLink(vdcLink);
+        persistentData.addLink(storageLink);
+        persistentData.addLink(templateLink);
+
+        // SCG:
+        // A simple user should not have permissions to obtain a datacenter repository, but at this
+        // point we have the datacenter repository and enterprise ids in the own target uri. So we
+        // can obtain the path where do the POST
+        // Assumption that to create a new object a user needs to get the parent object cannot be
+        // applied in this case
+        String editUri = getURI().getPath();
+        Pattern p = Pattern.compile("\\d+");
+        Matcher m = p.matcher(editUri);
+        m.find();
+        Integer idEnt = new Integer(m.group());
+        m.find();
+        Integer idDcRepo = new Integer(m.group());
+
+        AcceptedRequestDto<String> response =
+            context.getApi().getVirtualMachineTemplateApi()
+                .createPersistentVirtualMachineTemplate(idEnt, idDcRepo, persistentData);
+
+        return getTask(response);
+    }
+
+    // Children access
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Category+Resource#CategoryResource-Retrieveacategory"
+     *      > http://community.abiquo.com/display/ABI20/Category+Resource#CategoryResource-
+     *      Retrieveacategory</a>
+     */
+    public Category getCategory()
+    {
+        Integer categoryId = target.getIdFromLink(ParentLinkName.CATEGORY);
+        CategoryDto category = context.getApi().getConfigApi().getCategory(categoryId);
+        return wrap(context, Category.class, category);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/Abiquo/Volume+Resource#VolumeResource-Retrieveavolume"
+     *      > http://community.abiquo.com/display/Abiquo/Volume+Resource#VolumeResource-
+     *      Retrieveavolume</a>
+     */
+    public Volume getVolume()
+    {
+        if (this.isPersistent())
+        {
+            ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+            HttpResponse rp =
+                checkNotNull(utils.getAbiquoHttpClient().get(target.searchLink("volume")), "volume");
+
+            ParseXMLWithJAXB<VolumeManagementDto> parser =
+                new ParseXMLWithJAXB<VolumeManagementDto>(utils.getXml(),
+                    TypeLiteral.get(VolumeManagementDto.class));
+
+            VolumeManagementDto dto = parser.apply(rp);
+            return new Volume(context, dto);
+        }
+        return null;
+    }
+
+    public boolean isPersistent()
+    {
+        return target.searchLink("volume") != null;
+    }
+
+    // Parent access
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-RetrieveanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-
+     *      RetrieveanEnterprise</a>
+     */
+    public Enterprise getEnterprise()
+    {
+        Integer enterpriseId = target.getIdFromLink(ParentLinkName.ENTERPRISE);
+        return wrap(context, Enterprise.class,
+            context.getApi().getEnterpriseApi().getEnterprise(enterpriseId));
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Datacenter+Resource#DatacenterResource-RetrieveaDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Datacenter+Resource#DatacenterResource-
+     *      RetrieveaDatacenter</a>
+     */
+    public Datacenter getDatacenter()
+    {
+        Integer repositoryId = target.getIdFromLink(ParentLinkName.DATACENTER_REPOSITORY);
+        return wrap(context, Datacenter.class, context.getApi().getInfrastructureApi()
+            .getDatacenter(repositoryId));
+    }
+
+    /**
+     * List all the conversions for the virtual machine template.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Conversion+Resource#ConversionResource-ListConversions"
+     *      > http://community.abiquo.com/display/ABI20/Conversion+Resource#ConversionResource-
+     *      ListConversions</a>
+     * @return all the conversions of the virtual machine template
+     */
+    public List<Conversion> listConversions()
+    {
+        ConversionsDto convs =
+            context.getApi().getVirtualMachineTemplateApi().listConversions(target);
+        return wrap(context, Conversion.class, convs.getCollection());
+    }
+
+    /**
+     * List all the conversions for the virtual machine template matching the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The list all the conversions for the virtual machine template matching the given
+     *         filter.
+     */
+    public List<Conversion> listConversions(final Predicate<Conversion> filter)
+    {
+        return Lists.newLinkedList(filter(listConversions(), filter));
+    }
+
+    /**
+     * Gets a single conversion in the virtual machine template matching the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The conversion or <code>null</code> if none matched the given filter.
+     */
+    public Conversion findConversion(final Predicate<Conversion> filter)
+    {
+        return Iterables.getFirst(filter(listConversions(), filter), null);
+    }
+
+    /**
+     * List conversions for a virtual machine template.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Conversion+Resource#ConversionResource-ListConversions"
+     *      > http://community.abiquo.com/display/ABI20/Conversion+Resource#ConversionResource-
+     *      ListConversions</a>
+     * @param hypervisor, Optionally filter conversions compatible with the provided hypervisor
+     * @param state, Optionally filter conversions with the desired state
+     * @return all the conversions of the virtual machine template applying the constrains
+     */
+    public List<Conversion> listConversions(final HypervisorType hypervisor,
+        final ConversionState state)
+    {
+        ConversionsDto convs =
+            context
+                .getApi()
+                .getVirtualMachineTemplateApi()
+                .listConversions(
+                    target,
+                    ConversionOptions.builder().hypervisorType(hypervisor).conversionState(state)
+                        .build());
+        return wrap(context, Conversion.class, convs.getCollection());
+    }
+
+    /**
+     * Starts a new conversion for a virtual machine template.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Conversion+Resource#ConversionResource-RequestConversion"
+     *      > http://community.abiquo.com/display/ABI20/Conversion+Resource#ConversionResource-
+     *      RequestConversion</a>
+     * @param diskFormat, desired target format for the request template
+     * @return The task reference to track its progress
+     */
+    public AsyncTask requestConversion(final DiskFormatType diskFormat)
+    {
+        ConversionDto request = new ConversionDto();
+        request.setTargetFormat(diskFormat);
+
+        AcceptedRequestDto<String> taskRef =
+            context.getApi().getVirtualMachineTemplateApi()
+                .requestConversion(target, diskFormat, request);
+
+        return taskRef == null ? null : getTask(taskRef);
+    }
+
+    // Delegate methods
+    public int getCpuRequired()
+    {
+        return target.getCpuRequired();
+    }
+
+    public Date getCreationDate()
+    {
+        return target.getCreationDate();
+    }
+
+    public String getCreationUser()
+    {
+        return target.getCreationUser();
+    }
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    public long getDiskFileSize()
+    {
+        return target.getDiskFileSize();
+    }
+
+    public DiskFormatType getDiskFormatType()
+    {
+        return DiskFormatType.valueOf(target.getDiskFormatType());
+    }
+
+    public long getHdRequired()
+    {
+        return target.getHdRequired();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getPath()
+    {
+        return target.getPath();
+    }
+
+    public int getRamRequired()
+    {
+        return target.getRamRequired();
+    }
+
+    public boolean isChefEnabled()
+    {
+        return target.isChefEnabled();
+    }
+
+    public void setChefEnabled(final boolean chefEnabled)
+    {
+        target.setChefEnabled(chefEnabled);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getIconUrl()
+    {
+        return target.getIconUrl();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "VirtualMachineTemplate [id=" + getId() + ", cpuRequired=" + getCpuRequired()
+            + ", creationDate=" + getCreationDate() + ", creationUser=" + getCreationUser()
+            + ", description=" + getDescription() + ", diskFileSize=" + getDiskFileSize()
+            + ", diskFormatType=" + getDiskFormatType() + ", hdRequired=" + getHdRequired()
+            + ", name=" + getName() + ", path=" + getPath() + ", ramRequired=" + getRamRequired()
+            + ", chefEnabled=" + isChefEnabled() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Volume.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Volume.java
new file mode 100644
index 0000000..a8d4f4d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Volume.java
@@ -0,0 +1,250 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.infrastructure.Tier;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.VolumeState;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+
+/**
+ * Adds high level functionality to {@link VolumeManagementDto}.
+ * 
+ * @author Ignasi Barrera
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Volume+Resource">
+ *      http://community.abiquo.com/display/ABI20/Volume+Resource</a>
+ */
+@EnterpriseEdition
+public class Volume extends DomainWrapper<VolumeManagementDto>
+{
+    /** The default state for folumes. */
+    public static final VolumeState DEFAULT_STATE = VolumeState.DETACHED;
+
+    /** The virtual datacenter where the volume belongs. */
+    private VirtualDatacenter virtualDatacenter;
+
+    /** The tier where the volume belongs. */
+    private Tier tier;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Volume(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final VolumeManagementDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    public void delete()
+    {
+        context.getApi().getCloudApi().deleteVolume(target);
+        target = null;
+    }
+
+    public void save()
+    {
+        target = context.getApi().getCloudApi().createVolume(virtualDatacenter.unwrap(), target);
+    }
+
+    public AsyncTask update()
+    {
+        AcceptedRequestDto<String> taskRef = context.getApi().getCloudApi().updateVolume(target);
+        return taskRef == null ? null : getTask(taskRef);
+    }
+
+    // Parent access
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#VirtualDatacenterResource-RetrieveaVirtualDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Virtual+Datacenter+Resource#
+     *      VirtualDatacenterResource-RetrieveaVirtualDatacenter</a>
+     */
+    public VirtualDatacenter getVirtualDatacenter()
+    {
+        Integer virtualDatacenterId = target.getIdFromLink(ParentLinkName.VIRTUAL_DATACENTER);
+        VirtualDatacenterDto dto =
+            context.getApi().getCloudApi().getVirtualDatacenter(virtualDatacenterId);
+        virtualDatacenter = wrap(context, VirtualDatacenter.class, dto);
+        return virtualDatacenter;
+    }
+
+    /**
+     * TODO javadoc link
+     */
+    public Tier getTier()
+    {
+        Integer tierId = target.getIdFromLink(ParentLinkName.TIER);
+        TierDto dto =
+            context.getApi().getCloudApi().getStorageTier(virtualDatacenter.unwrap(), tierId);
+        tier = wrap(context, Tier.class, dto);
+        return tier;
+    }
+
+    // Actions
+
+    /**
+     * Move the volume to the given virtual datacenter.
+     * 
+     * @param newVirtualDatacenter The destination virtual datacenter.
+     */
+    public void moveTo(final VirtualDatacenter newVirtualDatacenter)
+    {
+        target =
+            context.getApi().getCloudApi().moveVolume(unwrap(), newVirtualDatacenter.unwrap());
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VirtualDatacenter virtualDatacenter, final Tier tier)
+    {
+        return new Builder(context, virtualDatacenter, tier);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name;
+
+        private String description;
+
+        private Long sizeInMb;
+
+        private VirtualDatacenter virtualDatacenter;
+
+        private Tier tier;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final VirtualDatacenter virtualDatacenter,
+            final Tier tier)
+        {
+            super();
+            checkNotNull(virtualDatacenter, ValidationErrors.NULL_RESOURCE
+                + VirtualDatacenter.class);
+            checkNotNull(tier, ValidationErrors.NULL_RESOURCE + Tier.class);
+            this.context = context;
+            this.virtualDatacenter = virtualDatacenter;
+            this.tier = tier;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder description(final String description)
+        {
+            this.description = description;
+            return this;
+        }
+
+        public Builder sizeInMb(final long sizeInMb)
+        {
+            this.sizeInMb = sizeInMb;
+            return this;
+        }
+
+        public Volume build()
+        {
+            VolumeManagementDto dto = new VolumeManagementDto();
+            dto.setName(name);
+            dto.setDescription(description);
+            dto.setSizeInMB(sizeInMb);
+            dto.setState(DEFAULT_STATE.name());
+
+            RESTLink link = tier.unwrap().searchLink("self");
+            checkNotNull(link, ValidationErrors.MISSING_REQUIRED_LINK);
+            dto.addLink(new RESTLink("tier", link.getHref()));
+
+            Volume volume = new Volume(context, dto);
+            volume.virtualDatacenter = virtualDatacenter;
+            volume.tier = tier;
+
+            return volume;
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getState()
+    {
+        return target.getState();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public long getSizeInMB()
+    {
+        return target.getSizeInMB();
+    }
+
+    public void setSizeInMB(final long sizeInMB)
+    {
+        target.setSizeInMB(sizeInMB);
+    }
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    public void setDescription(final String description)
+    {
+        target.setDescription(description);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Volume [id=" + getId() + ", state=" + getState() + ", name=" + getName()
+            + ", sizeInMB=" + getSizeInMB() + ", description=" + getDescription() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/ConversionOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/ConversionOptions.java
new file mode 100644
index 0000000..1d97f03
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/ConversionOptions.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.abiquo.model.enumerator.ConversionState;
+import com.abiquo.model.enumerator.HypervisorType;
+
+/**
+ * Available options to filter virtual machine template conversions
+ */
+public class ConversionOptions extends BaseHttpRequestOptions
+{
+
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        ConversionOptions options = new ConversionOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private HypervisorType hypervisorType;
+
+        private ConversionState conversionState;
+
+        /** Only conversions compatible with this hypervisor */
+        public Builder hypervisorType(final HypervisorType hypervisorType)
+        {
+            this.hypervisorType = hypervisorType;
+            return this;
+        }
+
+        /** Only conversions with the provided state */
+        public Builder conversionState(final ConversionState conversionState)
+        {
+            this.conversionState = conversionState;
+            return this;
+        }
+
+        public ConversionOptions build()
+        {
+            ConversionOptions options = new ConversionOptions();
+
+            if (hypervisorType != null)
+            {
+                options.queryParameters.put("hypervisor", hypervisorType.name());
+            }
+            if (conversionState != null)
+            {
+                options.queryParameters.put("state", conversionState.name());
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualApplianceOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualApplianceOptions.java
new file mode 100644
index 0000000..5042061
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualApplianceOptions.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query virtual appliances.
+ * 
+ * @author Francesc Montserrat
+ * @author Ignasi Barrera
+ */
+public class VirtualApplianceOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        VirtualApplianceOptions options = new VirtualApplianceOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+
+        private Boolean available;
+
+        public Builder available(final boolean available)
+        {
+            this.available = available;
+            return this;
+        }
+
+        public VirtualApplianceOptions build()
+        {
+            VirtualApplianceOptions options = new VirtualApplianceOptions();
+
+            if (available != null)
+            {
+                options.queryParameters.put("available", String.valueOf(available));
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualDatacenterOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualDatacenterOptions.java
new file mode 100644
index 0000000..783478f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualDatacenterOptions.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query virtual datacenters.
+ * 
+ * @author Francesc Montserrat
+ */
+public class VirtualDatacenterOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        VirtualDatacenterOptions options = new VirtualDatacenterOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private Integer datacenterId;
+
+        private Integer enterpriseId;
+
+        /**
+         * Set the optional datacenter.
+         */
+        public Builder datacenterId(final int datacenterId)
+        {
+            this.datacenterId = datacenterId;
+            return this;
+        }
+
+        /**
+         * Set the optional enterprise.
+         */
+        public Builder enterpriseId(final int enterpriseId)
+        {
+            this.enterpriseId = enterpriseId;
+            return this;
+        }
+
+        public VirtualDatacenterOptions build()
+        {
+            VirtualDatacenterOptions options = new VirtualDatacenterOptions();
+
+            if (datacenterId != null)
+            {
+                options.queryParameters.put("datacenter", datacenterId.toString());
+            }
+
+            if (enterpriseId != null)
+            {
+                options.queryParameters.put("enterprise", enterpriseId.toString());
+            }
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualMachineOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualMachineOptions.java
new file mode 100644
index 0000000..8675841
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualMachineOptions.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud.options;
+
+import org.jclouds.abiquo.domain.options.search.FilterOptions.BaseFilterOptionsBuilder;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query virtual machine.
+ * 
+ * @author Alessia Prete
+ */
+public class VirtualMachineOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        VirtualMachineOptions options = new VirtualMachineOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder extends BaseFilterOptionsBuilder<Builder>
+    {
+        private Boolean force;
+
+        public Builder force(final Boolean force)
+        {
+            this.force = force;
+            return this;
+        }
+
+        public VirtualMachineOptions build()
+        {
+            VirtualMachineOptions options = new VirtualMachineOptions();
+
+            if (force != null)
+            {
+                options.queryParameters.put("force", String.valueOf(force));
+            }
+
+            return addFilterOptions(options);
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualMachineTemplateOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualMachineTemplateOptions.java
new file mode 100644
index 0000000..6b6d2f1
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VirtualMachineTemplateOptions.java
@@ -0,0 +1,120 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud.options;
+
+import org.jclouds.abiquo.domain.config.Category;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.StatefulInclusion;
+
+/**
+ * Available options to query virtual machine templates.
+ * 
+ * @author Ignasi Barrera
+ */
+public class VirtualMachineTemplateOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        VirtualMachineTemplateOptions options = new VirtualMachineTemplateOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private StatefulInclusion persistent;
+
+        private HypervisorType hypervisorType;
+
+        private Category category;
+
+        private String categoryName;
+
+        private Integer idTemplate;
+
+        public Builder persistent(final StatefulInclusion persistent)
+        {
+            this.persistent = persistent;
+            return this;
+        }
+
+        public Builder hypervisorType(final HypervisorType hypervisorType)
+        {
+            this.hypervisorType = hypervisorType;
+            return this;
+        }
+
+        public Builder category(final Category category)
+        {
+            this.category = category;
+            return this;
+        }
+
+        public Builder categoryName(final String categoryName)
+        {
+            this.categoryName = categoryName;
+            return this;
+        }
+
+        public Builder idTemplate(final Integer idTemplate)
+        {
+            this.idTemplate = idTemplate;
+            return this;
+        }
+
+        public VirtualMachineTemplateOptions build()
+        {
+            VirtualMachineTemplateOptions options = new VirtualMachineTemplateOptions();
+
+            if (persistent != null)
+            {
+                options.queryParameters.put("stateful", persistent.name());
+            }
+            if (hypervisorType != null)
+            {
+                options.queryParameters.put("hypervisorTypeName", hypervisorType.name());
+            }
+            if (category != null)
+            {
+                options.queryParameters.put("categoryName", category.getName());
+            }
+
+            if (category == null && categoryName != null)
+            {
+                options.queryParameters.put("categoryName", categoryName);
+            }
+
+            if (idTemplate != null)
+            {
+                options.queryParameters.put("idTemplate", String.valueOf(idTemplate));
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VolumeOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VolumeOptions.java
new file mode 100644
index 0000000..66bc390
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/options/VolumeOptions.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud.options;
+
+import org.jclouds.abiquo.domain.options.search.FilterOptions.BaseFilterOptionsBuilder;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query volumes.
+ * 
+ * @author Ignasi Barrera
+ */
+@EnterpriseEdition
+public class VolumeOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        VolumeOptions options = new VolumeOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder extends BaseFilterOptionsBuilder<Builder>
+    {
+        private Boolean onlyAvailable;
+
+        public Builder onlyAvailable(final boolean onlyAvailable)
+        {
+            this.onlyAvailable = onlyAvailable;
+            return this;
+        }
+
+        public VolumeOptions build()
+        {
+            VolumeOptions options = new VolumeOptions();
+
+            if (onlyAvailable != null)
+            {
+                options.queryParameters.put("available", String.valueOf(onlyAvailable));
+            }
+
+            return addFilterOptions(options);
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Category.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Category.java
new file mode 100644
index 0000000..25ef1b2
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Category.java
@@ -0,0 +1,186 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.appslibrary.CategoryDto;
+
+/**
+ * Adds high level functionality to {@link CategoryDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Category+Resource">
+ *      http://community.abiquo.com/display/ABI20/Category+Resource</a>
+ */
+
+public class Category extends DomainWrapper<CategoryDto>
+{
+    /** The default value for the default category flag. */
+    private static final boolean DEFAULT_DEFAULT_CATEGORY = false;
+
+    /** The default value for the erasable flag. */
+    private static final boolean DEFAULT_ERASABLE = true;
+
+    /**
+     * Constructor to be used only by the builder. This resource cannot be created.
+     */
+    private Category(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final CategoryDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/Category+Resource#CategoryResource-Deleteacategory">
+     *      http://community.abiquo.com/display/ABI20/Category+Resource#CategoryResource-Deleteacategory</a>
+     */
+    public void delete()
+    {
+        context.getApi().getConfigApi().deleteCategory(target);
+        target = null;
+    }
+
+    /**
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/Category+Resource#CategoryResource-Createacategory">
+     *      http://community.abiquo.com/display/ABI20/Category+Resource#CategoryResource-Createacategory</a>
+     */
+    public void save()
+    {
+        target = context.getApi().getConfigApi().createCategory(target);
+    }
+
+    /**
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/Category+Resource#CategoryResource-Updateanexistingcategory">
+     *      http://community.abiquo.com/display/ABI20/Category+Resource#CategoryResource-Updateanexistingcategory</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getConfigApi().updateCategory(target);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        return new Builder(context);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name;
+
+        private Boolean erasable = DEFAULT_ERASABLE;
+
+        private Boolean defaultCategory = DEFAULT_DEFAULT_CATEGORY;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+        {
+            super();
+            this.context = context;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder defaultCategory(final boolean defaultCategory)
+        {
+            this.defaultCategory = defaultCategory;
+            return this;
+        }
+
+        public Builder erasable(final boolean erasable)
+        {
+            this.erasable = erasable;
+            return this;
+        }
+
+        public Category build()
+        {
+            CategoryDto dto = new CategoryDto();
+            dto.setErasable(erasable);
+            dto.setDefaultCategory(defaultCategory);
+            dto.setName(name);
+            Category category = new Category(context, dto);
+
+            return category;
+        }
+
+        public static Builder fromCategory(final Category in)
+        {
+            Builder builder =
+                Category.builder(in.context).name(in.getName()).erasable(in.isErasable())
+                    .defaultCategory(in.isDefaultCategory());
+
+            return builder;
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public boolean isDefaultCategory()
+    {
+        return target.isDefaultCategory();
+    }
+
+    public boolean isErasable()
+    {
+        return target.isErasable();
+    }
+
+    public void setDefaultCategory(final boolean defaultCategory)
+    {
+        target.setDefaultCategory(defaultCategory);
+    }
+
+    public void setErasable(final boolean erasable)
+    {
+        target.setErasable(erasable);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Currency.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Currency.java
new file mode 100644
index 0000000..d1fdb98
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Currency.java
@@ -0,0 +1,191 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.pricing.CurrencyDto;
+
+/**
+ * Adds high level functionality to {@link CurrencyDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Currency+Resource">
+ *      http://community.abiquo.com/display/ABI20/Currency+Resource</a>
+ */
+
+public class Currency extends DomainWrapper<CurrencyDto>
+{
+
+    /**
+     * Constructor to be used only by the builder. This resource cannot be created.
+     */
+    private Currency(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final CurrencyDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Currency+Resource#CurrencyResource-Deleteacurrency"
+     *      > http://community.abiquo.com/display/ABI20/Currency+Resource#CurrencyResource-
+     *      Deleteacurrency</a>
+     */
+    public void delete()
+    {
+        context.getApi().getPricingApi().deleteCurrency(target);
+        target = null;
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Currency+Resource#CurrencyResource-Createacurrency"
+     *      > http://community.abiquo.com/display/ABI20/Currency+Resource#CurrencyResource-
+     *      Createacurrency</a>
+     */
+    public void save()
+    {
+        target = context.getApi().getPricingApi().createCurrency(target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Currency+Resource#CurrencyResource-Updateanexistingcurrency"
+     *      > http://community.abiquo.com/display/ABI20/Currency+Resource#CurrencyResource-
+     *      Updateanexistingcurrency</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getPricingApi().updateCurrency(target);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        return new Builder(context);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name;
+
+        private String symbol;
+
+        private int digits;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+        {
+            super();
+            this.context = context;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder symbol(final String symbol)
+        {
+            this.symbol = symbol;
+            return this;
+        }
+
+        public Builder digits(final int digits)
+        {
+            this.digits = digits;
+            return this;
+        }
+
+        public Currency build()
+        {
+            CurrencyDto dto = new CurrencyDto();
+            dto.setName(name);
+            dto.setSymbol(symbol);
+            dto.setDigits(digits);
+            Currency currency = new Currency(context, dto);
+
+            return currency;
+        }
+
+        public static Builder fromCurrency(final Currency in)
+        {
+            Builder builder =
+                Currency.builder(in.context).name(in.getName()).symbol(in.getSymbol())
+                    .digits(in.getDigits());
+
+            return builder;
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public String getSymbol()
+    {
+        return target.getSymbol();
+    }
+
+    public void setSymbol(final String symbol)
+    {
+        target.setSymbol(symbol);
+    }
+
+    public int getDigits()
+    {
+        return target.getDigits();
+    }
+
+    public void setDigits(final int digits)
+    {
+        target.setDigits(digits);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Currency [id=" + getId() + ", name=" + getName() + ", symbol=" + getSymbol()
+            + ", digits=" + getDigits() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/License.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/License.java
new file mode 100644
index 0000000..f1c9d84
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/License.java
@@ -0,0 +1,142 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.config.LicenseDto;
+
+/**
+ * Adds high level functionality to {@link LicenseDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@EnterpriseEdition
+public class License extends DomainWrapper<LicenseDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected License(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final LicenseDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    public void remove()
+    {
+        context.getApi().getConfigApi().removeLicense(target);
+        target = null;
+    }
+
+    public void add()
+    {
+        target = context.getApi().getConfigApi().addLicense(target);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final String code)
+    {
+        return new Builder(context, code);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String code;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final String code)
+        {
+            super();
+            this.context = context;
+            this.code = code;
+        }
+
+        public Builder code(final String code)
+        {
+            this.code = code;
+            return this;
+        }
+
+        public License build()
+        {
+            LicenseDto dto = new LicenseDto();
+            dto.setCode(code);
+
+            License license = new License(context, dto);
+            return license;
+        }
+
+        public static Builder fromLicense(final License in)
+        {
+            return License.builder(in.context, in.getCode());
+        }
+    }
+
+    // Delegate methods
+
+    public String getCode()
+    {
+        return target.getCode();
+    }
+
+    public String getCustomerId()
+    {
+        return target.getCustomerid();
+    }
+
+    public String getEnabledIp()
+    {
+        return target.getEnabledip();
+    }
+
+    public String getExpiration()
+    {
+        return target.getExpiration();
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public Integer getNumCores()
+    {
+        return target.getNumcores();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "License [id=" + getId() + ", code=" + getCode() + ", customerId=" + getCustomerId()
+            + ", enabledIp=" + getEnabledIp() + ", expiration=" + getExpiration() + ", numCores="
+            + getNumCores() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Privilege.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Privilege.java
new file mode 100644
index 0000000..a35e4ee
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Privilege.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.PrivilegeDto;
+
+/**
+ * Adds high level functionality to {@link PrivilegeDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@EnterpriseEdition
+public class Privilege extends DomainWrapper<PrivilegeDto>
+{
+    /**
+     * Constructor to be used only by the builder. This resource cannot be created.
+     */
+    private Privilege(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final PrivilegeDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Privilege [id=" + getId() + ", name=" + getName() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/SystemProperty.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/SystemProperty.java
new file mode 100644
index 0000000..51c88c4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/SystemProperty.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.config.SystemPropertyDto;
+
+/**
+ * Adds high level functionality to {@link SystemPropertyDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/System+Property+resource">
+ *      http://community.abiquo.com/display/ABI20/System+Property+resource</a>
+ */
+
+public class SystemProperty extends DomainWrapper<SystemPropertyDto>
+{
+    /**
+     * Constructor to be used only by the builder. This resource cannot be created.
+     */
+    private SystemProperty(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final SystemPropertyDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/System+Property+resource#SystemPropertyresource-ModifyanexistingSystemProperty">
+     *      http://community.abiquo.com/display/ABI20/System+Property+resource#SystemPropertyresource-ModifyanexistingSystemProperty</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getConfigApi().updateSystemProperty(target);
+    }
+
+    // Delegate methods
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getValue()
+    {
+        return target.getValue();
+    }
+
+    public void setValue(final String value)
+    {
+        target.setValue(value);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "SystemPorperty [getName()=" + getName() + ", getValue()=" + getValue() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/IconOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/IconOptions.java
new file mode 100644
index 0000000..5c97581
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/IconOptions.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query icons.
+ * 
+ * @author Francesc Montserrat
+ */
+public class IconOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        IconOptions options = new IconOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private String path;
+
+        public Builder path(final String path)
+        {
+            this.path = path;
+            return this;
+        }
+
+        public IconOptions build()
+        {
+            IconOptions options = new IconOptions();
+            if (path != null)
+            {
+                options.queryParameters.put("path", path);
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/LicenseOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/LicenseOptions.java
new file mode 100644
index 0000000..7234fc2
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/LicenseOptions.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config.options;
+
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query licenses.
+ * 
+ * @author Francesc Montserrat
+ */
+@EnterpriseEdition
+public class LicenseOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        LicenseOptions options = new LicenseOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private Boolean active;
+
+        /**
+         * Search active licenses
+         */
+        public Builder active(final boolean active)
+        {
+            this.active = active;
+            return this;
+        }
+
+        /**
+         * Search inaactive licenses
+         */
+        public Builder inactive(final boolean inactive)
+        {
+            this.active = !inactive;
+            return this;
+        }
+
+        public LicenseOptions build()
+        {
+            LicenseOptions options = new LicenseOptions();
+            if (active != null)
+            {
+                options.queryParameters.put("active", active.toString());
+            }
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/PropertyOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/PropertyOptions.java
new file mode 100644
index 0000000..1f8a387
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/config/options/PropertyOptions.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query system properties.
+ * 
+ * @author Francesc Montserrat
+ */
+public class PropertyOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        PropertyOptions options = new PropertyOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private String component;
+
+        private String name;
+
+        public Builder component(final String component)
+        {
+            this.component = component;
+            return this;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public PropertyOptions build()
+        {
+            PropertyOptions options = new PropertyOptions();
+            if (component != null)
+            {
+                options.queryParameters.put("component", component.toString());
+            }
+
+            if (name != null)
+            {
+                options.queryParameters.put("name", name.toString());
+            }
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Enterprise.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Enterprise.java
new file mode 100644
index 0000000..f62ee8b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Enterprise.java
@@ -0,0 +1,1000 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.DomainWithLimitsWrapper;
+import org.jclouds.abiquo.domain.builder.LimitsBuilder;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+import org.jclouds.abiquo.domain.network.ExternalIp;
+import org.jclouds.abiquo.domain.network.ExternalNetwork;
+import org.jclouds.abiquo.domain.network.Network;
+import org.jclouds.abiquo.domain.network.UnmanagedIp;
+import org.jclouds.abiquo.domain.network.UnmanagedNetwork;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.abiquo.strategy.enterprise.ListVirtualMachineTemplates;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListDto;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListsDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.abiquo.server.core.cloud.VirtualDatacentersDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.DatacenterLimitsDto;
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.EnterprisePropertiesDto;
+import com.abiquo.server.core.enterprise.RolesDto;
+import com.abiquo.server.core.enterprise.UserDto;
+import com.abiquo.server.core.enterprise.UsersDto;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to {@link EnterpriseDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/EnterpriseResource">
+ *      http://community.abiquo.com/display/ABI20/EnterpriseResource</a>
+ */
+public class Enterprise extends DomainWithLimitsWrapper<EnterpriseDto>
+{
+    /** The default value for the reservation restricted flag. */
+    private static final boolean DEFAULT_RESERVATION_RESTRICTED = false;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Enterprise(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final EnterpriseDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Delete the enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-DeleteanexistingEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      DeleteanexistingEnterprise</a>
+     */
+    public void delete()
+    {
+        context.getApi().getEnterpriseApi().deleteEnterprise(target);
+        target = null;
+    }
+
+    /**
+     * Create a new enterprise in Abiquo.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-CreatesanewEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      CreatesanewEnterprise</a>
+     */
+    public void save()
+    {
+        target = context.getApi().getEnterpriseApi().createEnterprise(target);
+    }
+
+    /**
+     * Update emterprise information in the server with the data from this enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-Updateanexistingenterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      Updateanexistingenterprise</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getEnterpriseApi().updateEnterprise(target);
+    }
+
+    // Children access
+
+    /**
+     * Retrieve the list of virtual datacenters by this enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievealistofvitualdatacentersbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievealistofvitualdatacentersbyanEnterprise</a>
+     * @return List of virtual datacenters in this enterprise.
+     */
+    public List<VirtualDatacenter> listVirtualDatacenters()
+    {
+        VirtualDatacentersDto dto =
+            context.getApi().getEnterpriseApi().listVirtualDatacenters(target);
+        return wrap(context, VirtualDatacenter.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of virtual datacenters by this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievealistofvitualdatacentersbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievealistofvitualdatacentersbyanEnterprise</a>
+     * @return Filtered list of virtual datacenters in this enterprise.
+     */
+    public List<VirtualDatacenter> listVirtualDatacenters(final Predicate<VirtualDatacenter> filter)
+    {
+        return Lists.newLinkedList(filter(listVirtualDatacenters(), filter));
+    }
+
+    /**
+     * Retrieve a the first virtual datacenter matching the filter within the list of virtual
+     * datacenters by this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievealistofvitualdatacentersbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievealistofvitualdatacentersbyanEnterprise</a>
+     * @return First virtual datacenter matching the filter or <code>null</code> if the is none.
+     */
+    public VirtualDatacenter findVirtualDatacenter(final Predicate<VirtualDatacenter> filter)
+    {
+        return Iterables.getFirst(filter(listVirtualDatacenters(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of template definition lists of the enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Retrievealltemplatedefinitionlists"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Retrievealltemplatedefinitionlists</a>
+     * @return List of template definition lists of the enterprise.
+     */
+    public List<TemplateDefinitionList> listTemplateDefinitionLists()
+    {
+        TemplateDefinitionListsDto dto =
+            context.getApi().getEnterpriseApi().listTemplateDefinitionLists(target);
+        return wrap(context, TemplateDefinitionList.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of template definition lists from this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Retrievealltemplatedefinitionlists"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Retrievealltemplatedefinitionlists</a>
+     * @return Filtered list of template definition lists of the enterprise.
+     */
+    public List<TemplateDefinitionList> listTemplateDefinitionLists(
+        final Predicate<TemplateDefinitionList> filter)
+    {
+        return Lists.newLinkedList(filter(listTemplateDefinitionLists(), filter));
+    }
+
+    /**
+     * Retrieve the first template definition list matching the filter within the list.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Retrievealltemplatedefinitionlists"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Retrievealltemplatedefinitionlists</a>
+     * @return First template definition list matching the filter or <code>null</code> if the is
+     *         none.
+     */
+    public TemplateDefinitionList findTemplateDefinitionList(
+        final Predicate<TemplateDefinitionList> filter)
+    {
+        return Iterables.getFirst(filter(listTemplateDefinitionLists(), filter), null);
+    }
+
+    /**
+     * Retrieve a single template definition list.
+     * 
+     * @param id Unique ID of the template definition list for this enterprise.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Retrieveatemplatedefinitionlist"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Retrieveatemplatedefinitionlist</a>
+     * @return Template definition with the given id or <code>null</code> if it does not exist.
+     */
+    public TemplateDefinitionList getTemplateDefinitionList(final Integer id)
+    {
+        TemplateDefinitionListDto templateList =
+            context.getApi().getEnterpriseApi().getTemplateDefinitionList(target, id);
+        return wrap(context, TemplateDefinitionList.class, templateList);
+    }
+
+    /**
+     * Retrieve the list of datacenter limits by enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterLimitsResource#DatacenterLimitsResource-Retrievelimitsbyenterprise"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterLimitsResource#
+     *      DatacenterLimitsResource-Retrievelimitsbyenterprise</a>
+     * @return List of datacenter limits by enterprise.
+     */
+    public List<Limits> listLimits()
+    {
+        DatacentersLimitsDto dto = context.getApi().getEnterpriseApi().listLimits(this.unwrap());
+        return wrap(context, Limits.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of datacenter limits by enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterLimitsResource#DatacenterLimitsResource-Retrievelimitsbyenterprise"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterLimitsResource#
+     *      DatacenterLimitsResource-Retrievelimitsbyenterprise</a>
+     * @return Filtered list of datacenter limits by enterprise.
+     */
+    public List<Limits> listLimits(final Predicate<Limits> filter)
+    {
+        return Lists.newLinkedList(filter(listLimits(), filter));
+    }
+
+    /**
+     * Retrieve the first datacenter limits matching the filter within the list of datacenter limits
+     * by enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterLimitsResource#DatacenterLimitsResource-Retrievelimitsbyenterprise"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterLimitsResource#
+     *      DatacenterLimitsResource-Retrievelimitsbyenterprise</a>
+     * @return First datacenter limits matching the filter or <code>null</code> if there is none.
+     */
+    public Limits findLimits(final Predicate<Limits> filter)
+    {
+        return Iterables.getFirst(filter(listLimits(), filter), null);
+    }
+
+    /**
+     * Retrieve the defined properties of the given enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterprisePropertiesResource#EnterprisePropertiesResource-Retrievethepropertiesforanenterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterprisePropertiesResource#
+     *      EnterprisePropertiesResource-Retrievethepropertiesforanenterprise</a>
+     * @return The defined properties of the given enterprise.
+     */
+    public EnterpriseProperties getEnterpriseProperties()
+    {
+        EnterprisePropertiesDto dto =
+            context.getApi().getEnterpriseApi().getEnterpriseProperties(this.unwrap());
+        return wrap(context, EnterpriseProperties.class, dto);
+    }
+
+    /**
+     * Retrieve the list of users of this enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/UserResource#UserResource-Retrievealistofusers"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/UserResource#UserResource-Retrievealistofusers
+     *      </a>
+     * @return List of users of this enterprise.
+     */
+    public List<User> listUsers()
+    {
+        UsersDto dto = context.getApi().getEnterpriseApi().listUsers(this.unwrap());
+        return wrap(context, User.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of users of this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/UserResource#UserResource-Retrievealistofusers"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/UserResource#UserResource-Retrievealistofusers
+     *      </a>
+     * @return Filtered list of users of this enterprise.
+     */
+    public List<User> listUsers(final Predicate<User> filter)
+    {
+        return Lists.newLinkedList(filter(listUsers(), filter));
+    }
+
+    /**
+     * Retrieve the first user matching the filter within the list of users of this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/UserResource#UserResource-Retrievealistofusers"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/UserResource#UserResource-Retrievealistofusers
+     *      </a>
+     * @return First user matching the filter or <code>null</code> if there is none.
+     */
+    public User findUser(final Predicate<User> filter)
+    {
+        return Iterables.getFirst(filter(listUsers(), filter), null);
+    }
+
+    /**
+     * Retrieve a single user.
+     * 
+     * @param id Unique ID of the user in this enterprise.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/UserResource#UserResource-Retrieveauser" >
+     *      http://community.abiquo.com/display/ABI20/UserResource#UserResource-Retrieveauser</a>
+     * @return User with the given id or <code>null</code> if it does not exist.
+     */
+    public User getUser(final Integer id)
+    {
+        UserDto user = context.getApi().getEnterpriseApi().getUser(target, id);
+        return wrap(context, User.class, user);
+    }
+
+    /**
+     * Retrieve the list of roles defined by this enterprise.
+     * 
+     * @return List of roles by this enterprise.
+     */
+    public List<Role> listRoles()
+    {
+        RolesDto dto = context.getApi().getAdminApi().listRoles(target);
+        return wrap(context, Role.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of roles defined by this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @return Filtered list of roles by this enterprise.
+     */
+    public List<Role> listRoles(final Predicate<Role> filter)
+    {
+        return Lists.newLinkedList(filter(listRoles(), filter));
+    }
+
+    /**
+     * Retrieve the first role matching the filter within the list of roles defined by this
+     * enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @return First role matching the filter or <code>null</code> if there is none.
+     */
+    public Role findRole(final Predicate<Role> filter)
+    {
+        return Iterables.getFirst(filter(listRoles(), filter), null);
+    }
+
+    public List<VirtualMachineTemplate> listTemplatesInRepository(final Datacenter datacenter)
+    {
+        VirtualMachineTemplatesDto dto =
+            context.getApi().getVirtualMachineTemplateApi()
+                .listVirtualMachineTemplates(target.getId(), datacenter.getId());
+        return wrap(context, VirtualMachineTemplate.class, dto.getCollection());
+    }
+
+    public List<VirtualMachineTemplate> listTemplatesInRepository(final Datacenter datacenter,
+        final Predicate<VirtualMachineTemplate> filter)
+    {
+        return Lists.newLinkedList(filter(listTemplatesInRepository(datacenter), filter));
+    }
+
+    public VirtualMachineTemplate findTemplateInRepository(final Datacenter datacenter,
+        final Predicate<VirtualMachineTemplate> filter)
+    {
+        return Iterables.getFirst(filter(listTemplatesInRepository(datacenter), filter), null);
+    }
+
+    public VirtualMachineTemplate getTemplateInRepository(final Datacenter datacenter,
+        final Integer id)
+    {
+        VirtualMachineTemplateDto template =
+            context.getApi().getVirtualMachineTemplateApi()
+                .getVirtualMachineTemplate(target.getId(), datacenter.getId(), id);
+        return wrap(context, VirtualMachineTemplate.class, template);
+    }
+
+    public List<VirtualMachineTemplate> listTemplates()
+    {
+        ListVirtualMachineTemplates strategy =
+            context.getUtils().getInjector().getInstance(ListVirtualMachineTemplates.class);
+        return Lists.newLinkedList(strategy.execute(this));
+    }
+
+    public List<VirtualMachineTemplate> listTemplates(final Predicate<VirtualMachineTemplate> filter)
+    {
+        ListVirtualMachineTemplates strategy =
+            context.getUtils().getInjector().getInstance(ListVirtualMachineTemplates.class);
+        return Lists.newLinkedList(strategy.execute(this, filter));
+    }
+
+    public VirtualMachineTemplate findTemplate(final Predicate<VirtualMachineTemplate> filter)
+    {
+        ListVirtualMachineTemplates strategy =
+            context.getUtils().getInjector().getInstance(ListVirtualMachineTemplates.class);
+        return Iterables.getFirst(strategy.execute(this, filter), null);
+    }
+
+    public List<Datacenter> listAllowedDatacenters()
+    {
+        DatacentersDto datacenters =
+            context.getApi().getEnterpriseApi().listAllowedDatacenters(target.getId());
+        return wrap(context, Datacenter.class, datacenters.getCollection());
+    }
+
+    public List<Datacenter> listAllowedDatacenters(final Predicate<Datacenter> filter)
+    {
+        return Lists.newLinkedList(filter(listAllowedDatacenters(), filter));
+    }
+
+    public Datacenter findAllowedDatacenter(final Predicate<Datacenter> filter)
+    {
+        return Iterables.getFirst(filter(listAllowedDatacenters(), filter), null);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-Getthelistofexternalnetworks"
+     *      > http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-
+     *      Getthelistofexternalnetworks</a>
+     */
+    @EnterpriseEdition
+    public List<ExternalNetwork> listExternalNetworks(final Datacenter datacenter)
+    {
+        DatacenterLimitsDto limitForDatacenter = getLimits(datacenter);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response =
+            utils.getAbiquoHttpClient().get(limitForDatacenter.searchLink("externalnetworks"));
+
+        ParseXMLWithJAXB<VLANNetworksDto> parser =
+            new ParseXMLWithJAXB<VLANNetworksDto>(utils.getXml(),
+                TypeLiteral.get(VLANNetworksDto.class));
+
+        return wrap(context, ExternalNetwork.class, parser.apply(response).getCollection());
+    }
+
+    @EnterpriseEdition
+    public List<ExternalNetwork> listExternalNetworks(final Datacenter datacenter,
+        final Predicate<Network<ExternalIp>> filter)
+    {
+        return Lists.newLinkedList(filter(listExternalNetworks(datacenter), filter));
+    }
+
+    @EnterpriseEdition
+    public ExternalNetwork findExternalNetwork(final Datacenter datacenter,
+        final Predicate<Network<ExternalIp>> filter)
+    {
+        return Iterables.getFirst(filter(listExternalNetworks(datacenter), filter), null);
+    }
+
+    @EnterpriseEdition
+    public List<UnmanagedNetwork> listUnmanagedNetworks(final Datacenter datacenter)
+    {
+        DatacenterLimitsDto limitForDatacenter = getLimits(datacenter);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        // The "rel" for the unmanaged networks is the same than teh one used for external networks
+        HttpResponse response =
+            utils.getAbiquoHttpClient().get(limitForDatacenter.searchLink("externalnetworks"));
+
+        ParseXMLWithJAXB<VLANNetworksDto> parser =
+            new ParseXMLWithJAXB<VLANNetworksDto>(utils.getXml(),
+                TypeLiteral.get(VLANNetworksDto.class));
+
+        return wrap(context, UnmanagedNetwork.class, parser.apply(response).getCollection());
+    }
+
+    @EnterpriseEdition
+    public List<UnmanagedNetwork> listUnmanagedNetworks(final Datacenter datacenter,
+        final Predicate<Network<UnmanagedIp>> filter)
+    {
+        return Lists.newLinkedList(filter(listUnmanagedNetworks(datacenter), filter));
+    }
+
+    @EnterpriseEdition
+    public UnmanagedNetwork findUnmanagedNetwork(final Datacenter datacenter,
+        final Predicate<Network<UnmanagedIp>> filter)
+    {
+        return Iterables.getFirst(filter(listUnmanagedNetworks(datacenter), filter), null);
+    }
+
+    /**
+     * Retrieve the list of virtual appliances by this enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievethelistofvirtualappliancesbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievethelistofvirtualappliancesbyanEnterprise</a>
+     * @return List of virtual appliances by this enterprise.
+     */
+    public List<VirtualAppliance> listVirtualAppliances()
+    {
+        VirtualAppliancesDto virtualAppliances =
+            context.getApi().getEnterpriseApi().listVirtualAppliances(target);
+        return wrap(context, VirtualAppliance.class, virtualAppliances.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of virtual appliances by this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievethelistofvirtualappliancesbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievethelistofvirtualappliancesbyanEnterprise</a>
+     * @return Filtered list of virtual appliances by this enterprise.
+     */
+    public List<VirtualAppliance> listVirtualAppliances(final Predicate<VirtualAppliance> filter)
+    {
+        return Lists.newLinkedList(filter(listVirtualAppliances(), filter));
+    }
+
+    /**
+     * Retrieve the first virtual appliance matching the filter within the list of virtual
+     * appliances in this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievethelistofvirtualappliancesbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievethelistofvirtualappliancesbyanEnterprise</a>
+     * @return First virtual machine matching the filter or <code>null</code> if the is none.
+     */
+    public VirtualAppliance findVirtualAppliance(final Predicate<VirtualAppliance> filter)
+    {
+        return Iterables.getFirst(filter(listVirtualAppliances(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of virtual machines by this enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievealistofvirtualmachinesbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievealistofvirtualmachinesbyanEnterprise</a>
+     * @return List of virtual machines by this enterprise.
+     */
+    public List<VirtualMachine> listVirtualMachines()
+    {
+        VirtualMachinesWithNodeExtendedDto machines =
+            context.getApi().getEnterpriseApi().listVirtualMachines(target);
+        return wrap(context, VirtualMachine.class, machines.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of virtual machines by this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievealistofvirtualmachinesbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievealistofvirtualmachinesbyanEnterprise</a>
+     * @return Filtered list of virtual machines by this enterprise.
+     */
+    public List<VirtualMachine> listVirtualMachines(final Predicate<VirtualMachine> filter)
+    {
+        return Lists.newLinkedList(filter(listVirtualMachines(), filter));
+    }
+
+    /**
+     * Retrieve the first virtual machine matching the filter within the list of virtual machines in
+     * this enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-RetrievealistofvirtualmachinesbyanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/EnterpriseResource#EnterpriseResource-
+     *      RetrievealistofvirtualmachinesbyanEnterprise</a>
+     * @return First virtual machine matching the filter or <code>null</code> if the is none.
+     */
+    public VirtualMachine findVirtualMachine(final Predicate<VirtualMachine> filter)
+    {
+        return Iterables.getFirst(filter(listVirtualMachines(), filter), null);
+    }
+
+    public List<Machine> listReservedMachines()
+    {
+        MachinesDto machines = context.getApi().getEnterpriseApi().listReservedMachines(target);
+        return wrap(context, Machine.class, machines.getCollection());
+    }
+
+    public List<VirtualMachine> listReservedMachines(final Predicate<VirtualMachine> filter)
+    {
+        return Lists.newLinkedList(filter(listVirtualMachines(), filter));
+    }
+
+    public VirtualMachine findReservedMachine(final Predicate<VirtualMachine> filter)
+    {
+        return Iterables.getFirst(filter(listVirtualMachines(), filter), null);
+    }
+
+    // Actions
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Datacenter+Repository+Resource#DatacenterRepositoryResource-SynchronizetheDatacenterRepositorywiththerepository"
+     *      > http://community.abiquo.com/display/ABI20/Datacenter+Repository+Resource#
+     *      DatacenterRepositoryResource-SynchronizetheDatacenterRepositorywiththerepository</a>
+     */
+    public void refreshTemplateRepository(final Datacenter datacenter)
+    {
+        context.getApi().getEnterpriseApi()
+            .refreshTemplateRepository(target.getId(), datacenter.getId());
+    }
+
+    /**
+     * Allows the given datacenter to be used by this enterprise. Creates a {@link Limits} object if
+     * not exists.
+     * 
+     * @param datacenter The datacenter.
+     * @return Default datacenter limits of the enterprise for the given datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Datacenter+Limits+Resource#DatacenterLimitsResource-CreateanewLimitforanenterpriseinadatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Datacenter+Limits+Resource#
+     *      DatacenterLimitsResource-CreateanewLimitforanenterpriseinadatacenter</a>
+     */
+    public Limits allowDatacenter(final Datacenter datacenter)
+    {
+        DatacenterLimitsDto dto;
+
+        try
+        {
+            // Create new limits
+            Limits limits = Limits.builder(context).build();
+
+            // Save new limits
+            dto =
+                context.getApi().getEnterpriseApi()
+                    .createLimits(target, datacenter.unwrap(), limits.unwrap());
+        }
+        catch (AbiquoException ex)
+        {
+            // Controlled error to allow duplicated authorizations
+            if (ex.hasError("LIMIT-7"))
+            {
+                DatacentersLimitsDto limits =
+                    context.getApi().getEnterpriseApi().getLimits(target, datacenter.unwrap());
+                // Should be only one limit
+                dto = limits.getCollection().get(0);
+            }
+            else
+            {
+                throw ex;
+            }
+        }
+
+        return wrap(context, Limits.class, dto);
+    }
+
+    /**
+     * Prohibe the given datacenter to be used by this enterprise. Deletes a {@link Limits} object.
+     * 
+     * @param datacenter The datacenter.
+     * @return Default datacenter limits of the enterprise for the given datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Datacenter+Limits+Resource#DatacenterLimitsResource-Deleteanexistinglimitforanenterpriseinadatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Datacenter+Limits+Resource#
+     *      DatacenterLimitsResource-Deleteanexistinglimitforanenterpriseinadatacenter</a>
+     */
+    public void prohibitDatacenter(final Datacenter datacenter)
+    {
+        // Get limits
+        DatacentersLimitsDto dto =
+            context.getApi().getEnterpriseApi().getLimits(target, datacenter.unwrap());
+
+        // Delete limits (if any)
+        if (dto != null && !dto.isEmpty())
+        {
+            // Should be only one limit
+            context.getApi().getEnterpriseApi().deleteLimits(dto.getCollection().get(0));
+        }
+    }
+
+    /**
+     * Disables chef in the enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-DisableChefinanexistingEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-
+     *      DisableChefinanexistingEnterprise</a>
+     */
+    public void disableChef()
+    {
+        target.setChefClient(null);
+        target.setChefClientCertificate(null);
+        target.setChefURL(null);
+        target.setChefValidator(null);
+        target.setChefValidatorCertificate(null);
+        update();
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        return new Builder(context);
+    }
+
+    public static class Builder extends LimitsBuilder<Builder>
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name;
+
+        protected Long repositorySoft = Long.valueOf(DEFAULT_LIMITS);
+
+        protected Long repositoryHard = Long.valueOf(DEFAULT_LIMITS);
+
+        private Boolean isReservationRestricted = DEFAULT_RESERVATION_RESTRICTED;
+
+        private String chefURL;
+
+        private String chefClient;
+
+        private String chefValidator;
+
+        private String chefApiCertificate;
+
+        private String chefValidatorCertificate;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+        {
+            super();
+            this.context = context;
+        }
+
+        public Builder isReservationRestricted(final boolean isReservationRestricted)
+        {
+            this.isReservationRestricted = isReservationRestricted;
+            return this;
+        }
+
+        public Builder chefURL(final String chefURL)
+        {
+            this.chefURL = chefURL;
+            return this;
+        }
+
+        public Builder chefClient(final String chefClient)
+        {
+            this.chefClient = chefClient;
+            return this;
+        }
+
+        public Builder chefApiCertificate(final String chefApiCertificate)
+        {
+            this.chefApiCertificate = chefApiCertificate;
+            return this;
+        }
+
+        public Builder chefValidator(final String chefValidator)
+        {
+            this.chefValidator = chefValidator;
+            return this;
+        }
+
+        public Builder chefValidatorCertificate(final String chefValidatorCertificate)
+        {
+            this.chefValidatorCertificate = chefValidatorCertificate;
+            return this;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder repositoryLimits(final long soft, final long hard)
+        {
+            this.repositorySoft = soft;
+            this.repositoryHard = hard;
+            return this;
+        }
+
+        public Enterprise build()
+        {
+            EnterpriseDto dto = new EnterpriseDto();
+            dto.setName(name);
+            dto.setRamLimitsInMb(ramSoftLimitInMb, ramHardLimitInMb);
+            dto.setCpuCountLimits(cpuCountSoftLimit, cpuCountHardLimit);
+            dto.setHdLimitsInMb(hdSoftLimitInMb, hdHardLimitInMb);
+            dto.setStorageLimits(storageSoft, storageHard);
+            dto.setVlansLimits(vlansSoft, vlansHard);
+            dto.setPublicIPLimits(publicIpsSoft, publicIpsHard);
+            dto.setRepositoryLimits(repositorySoft, repositoryHard);
+            dto.setIsReservationRestricted(isReservationRestricted);
+            dto.setChefClient(chefClient);
+            dto.setChefClientCertificate(chefApiCertificate);
+            dto.setChefURL(chefURL);
+            dto.setChefValidator(chefValidator);
+            dto.setChefValidatorCertificate(chefValidatorCertificate);
+
+            return new Enterprise(context, dto);
+        }
+
+        public static Builder fromEnterprise(final Enterprise in)
+        {
+            return Enterprise.builder(in.context).name(in.getName())
+                .ramLimits(in.getRamSoftLimitInMb(), in.getRamHardLimitInMb())
+                .cpuCountLimits(in.getCpuCountSoftLimit(), in.getCpuCountHardLimit())
+                .hdLimitsInMb(in.getHdSoftLimitInMb(), in.getHdHardLimitInMb())
+                .storageLimits(in.getStorageSoft(), in.getStorageHard())
+                .vlansLimits(in.getVlansSoft(), in.getVlansHard())
+                .publicIpsLimits(in.getPublicIpsSoft(), in.getPublicIpsHard())
+                .repositoryLimits(in.getRepositorySoft(), in.getRepositoryHard())
+                .isReservationRestricted(in.getIsReservationRestricted())
+                .chefClient(in.getChefClient()).chefApiCertificate(in.getChefApiCertificate())
+                .chefURL(in.getChefURL()).chefValidator(in.getChefValidator())
+                .chefValidatorCertificate(in.getChefValidatorCertificate());
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public boolean getIsReservationRestricted()
+    {
+        return target.getIsReservationRestricted();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public long getRepositoryHard()
+    {
+        return target.getRepositoryHard();
+    }
+
+    public long getRepositorySoft()
+    {
+        return target.getRepositorySoft();
+    }
+
+    public void setIsReservationRestricted(final boolean isReservationRestricted)
+    {
+        target.setIsReservationRestricted(isReservationRestricted);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setRepositoryHard(final long repositoryHard)
+    {
+        target.setRepositoryHard(repositoryHard);
+    }
+
+    public void setRepositoryLimits(final long soft, final long hard)
+    {
+        target.setRepositoryLimits(soft, hard);
+    }
+
+    public void setRepositorySoft(final long repositorySoft)
+    {
+        target.setRepositorySoft(repositorySoft);
+    }
+
+    public String getChefClient()
+    {
+        return target.getChefClient();
+    }
+
+    public String getChefApiCertificate()
+    {
+        return target.getChefClientCertificate();
+    }
+
+    public String getChefURL()
+    {
+        return target.getChefURL();
+    }
+
+    public String getChefValidator()
+    {
+        return target.getChefValidator();
+    }
+
+    public String getChefValidatorCertificate()
+    {
+        return target.getChefValidatorCertificate();
+    }
+
+    public void setChefClient(final String chefClient)
+    {
+        target.setChefClient(chefClient);
+    }
+
+    public void setChefClientCertificate(final String chefClientCertificate)
+    {
+        target.setChefClientCertificate(chefClientCertificate);
+    }
+
+    public void setChefURL(final String chefURL)
+    {
+        target.setChefURL(chefURL);
+    }
+
+    public void setChefValidator(final String chefValidator)
+    {
+        target.setChefValidator(chefValidator);
+    }
+
+    public void setChefValidatorCertificate(final String chefValidatorCertificate)
+    {
+        target.setChefValidatorCertificate(chefValidatorCertificate);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Enterprise [id=" + getId() + ", isReservationRestricted="
+            + getIsReservationRestricted() + ", name=" + getName() + "]";
+    }
+
+    private DatacenterLimitsDto getLimits(final Datacenter datacenter)
+    {
+        DatacentersLimitsDto limits = context.getApi().getEnterpriseApi().listLimits(target);
+
+        return Iterables.find(limits.getCollection(), new Predicate<DatacenterLimitsDto>()
+        {
+            @Override
+            public boolean apply(final DatacenterLimitsDto input)
+            {
+                RESTLink datacenterLink = input.searchLink("datacenter");
+                return datacenterLink != null
+                    && datacenterLink.getHref().equals(datacenter.unwrap().getEditLink().getHref());
+            }
+        });
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/EnterpriseProperties.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/EnterpriseProperties.java
new file mode 100644
index 0000000..dba92be
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/EnterpriseProperties.java
@@ -0,0 +1,88 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy 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.abiquo.domain.enterprise;
+
+import java.util.Map;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.EnterprisePropertiesDto;
+
+/**
+ * Adds high level functionality to {@link EnterprisePropertiesDto}.
+ * 
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Enterprise+Properties+Resource">
+ *      http://community.abiquo.com/display/ABI20/Enterprise+Properties+Resource</a>
+ */
+@EnterpriseEdition
+public class EnterpriseProperties extends DomainWrapper<EnterprisePropertiesDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected EnterpriseProperties(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final EnterprisePropertiesDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Enterprise+Properties+Resource#EnterprisePropertiesResource-UpdatesthepropertiesforanEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/Enterprise+Properties+Resource#
+     *      EnterprisePropertiesResource-UpdatesthepropertiesforanEnterprise</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getEnterpriseApi().updateEnterpriseProperties(target);
+    }
+
+    // Parent access
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-RetrieveaEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-
+     *      RetrieveaEnterprise</a>
+     */
+    public Enterprise getEnterprise()
+    {
+        Integer enterpriseId = target.getIdFromLink(ParentLinkName.ENTERPRISE);
+        return wrap(context, Enterprise.class, context.getApi().getEnterpriseApi()
+            .getEnterprise(enterpriseId));
+    }
+
+    // Delegate methods
+    public Map<String, String> getProperties()
+    {
+        return target.getProperties();
+    }
+
+    public void setProperties(final Map<String, String> properties)
+    {
+        target.setProperties(properties);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Limits.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Limits.java
new file mode 100644
index 0000000..3e31eb0
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Limits.java
@@ -0,0 +1,165 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWithLimitsWrapper;
+import org.jclouds.abiquo.domain.builder.LimitsBuilder;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.DatacenterLimitsDto;
+
+/**
+ * Adds high level functionality to {@link DatacenterLimitsDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Datacenter+Limits+Resource">
+ *      http://community.abiquo.com/display/ABI20/Datacenter+Limits+Resource</a>
+ */
+public class Limits extends DomainWithLimitsWrapper<DatacenterLimitsDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Limits(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final DatacenterLimitsDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/Datacenter+Limits+Resource#DatacenterLimitsResource-UpdatesanexistingLimitforanenterpriseinadatacenter">
+     *      http://community.abiquo.com/display/ABI20/Datacenter+Limits+Resource#DatacenterLimitsResource-UpdatesanexistingLimitforanenterpriseinadatacenter</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getEnterpriseApi().updateLimits(target);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        return new Builder(context);
+    }
+
+    public static class Builder extends LimitsBuilder<Builder>
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        protected Long repositorySoft = Long.valueOf(DEFAULT_LIMITS);
+
+        protected Long repositoryHard = Long.valueOf(DEFAULT_LIMITS);
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+        {
+            super();
+            this.context = context;
+        }
+
+        public Builder repositoryLimits(final long soft, final long hard)
+        {
+            this.repositorySoft = soft;
+            this.repositoryHard = hard;
+            return this;
+        }
+
+        public Limits build()
+        {
+            DatacenterLimitsDto dto = new DatacenterLimitsDto();
+            dto.setRamLimitsInMb(ramSoftLimitInMb, ramHardLimitInMb);
+            dto.setCpuCountLimits(cpuCountSoftLimit, cpuCountHardLimit);
+            dto.setHdLimitsInMb(hdSoftLimitInMb, hdHardLimitInMb);
+            dto.setStorageLimits(storageSoft, storageHard);
+            dto.setVlansLimits(vlansSoft, vlansHard);
+            dto.setPublicIPLimits(publicIpsSoft, publicIpsHard);
+            dto.setRepositoryHardLimitsInMb(repositoryHard);
+            dto.setRepositorySoftLimitsInMb(repositorySoft);
+
+            Limits limits = new Limits(context, dto);
+
+            return limits;
+        }
+
+        public static Builder fromEnterprise(final Limits in)
+        {
+            return Limits.builder(in.context)
+                .ramLimits(in.getRamSoftLimitInMb(), in.getRamHardLimitInMb())
+                .cpuCountLimits(in.getCpuCountSoftLimit(), in.getCpuCountHardLimit())
+                .hdLimitsInMb(in.getHdSoftLimitInMb(), in.getHdHardLimitInMb())
+                .storageLimits(in.getStorageSoft(), in.getStorageHard())
+                .vlansLimits(in.getVlansSoft(), in.getVlansHard())
+                .publicIpsLimits(in.getPublicIpsSoft(), in.getPublicIpsHard())
+                .repositoryLimits(in.getRepositorySoft(), in.getRepositoryHard());
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public long getRepositoryHard()
+    {
+        return target.getRepositoryHardLimitsInMb();
+    }
+
+    public long getRepositorySoft()
+    {
+        return target.getRepositorySoftLimitsInMb();
+    }
+
+    public void setRepositoryHard(final long repositoryHard)
+    {
+        target.setRepositoryHardLimitsInMb(repositoryHard);
+    }
+
+    public void setRepositoryLimits(final long soft, final long hard)
+    {
+        target.setRepositoryHardLimitsInMb(hard);
+        target.setRepositorySoftLimitsInMb(soft);
+    }
+
+    public void setRepositorySoft(final long repositorySoft)
+    {
+        target.setRepositorySoftLimitsInMb(repositorySoft);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Limits [id=" + getId() + ", repositoryHard=" + getRepositoryHard()
+            + ", repositorySoft=" + getRepositorySoft() + ", cpuCounthard="
+            + getCpuCountHardLimit() + ", cpuCountSoft=" + getCpuCountSoftLimit() + ", hdHardInMB="
+            + getHdHardLimitInMb() + ", hdSoftInMB=" + getHdSoftLimitInMb() + ", publicIPsHard="
+            + getPublicIpsHard() + ", publicIpsSoft=" + getPublicIpsSoft() + ", ramHardInMB="
+            + getRamHardLimitInMb() + ", ramSoftInMB=" + getRamSoftLimitInMb() + ", storageHard="
+            + getStorageHard() + ", storageSoft=" + getStorageSoft() + ", vlansHard="
+            + getVlansHard() + ", vlansSoft=" + getVlansSoft() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Role.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Role.java
new file mode 100644
index 0000000..b12b622
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/Role.java
@@ -0,0 +1,250 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.config.Privilege;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.enterprise.PrivilegesDto;
+import com.abiquo.server.core.enterprise.RoleDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link RoleDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Roles+Resource">
+ *      http://community.abiquo.com/display/ABI20/Roles+Resource</a>
+ */
+public class Role extends DomainWrapper<RoleDto>
+{
+    /** Default active value of the user */
+    private static final boolean DEFAULT_BLOCKED = false;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Role(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final RoleDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Roles+Resource#RolesResource-DeleteanexistingRole"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Roles+Resource#RolesResource-DeleteanexistingRole
+     *      </a>
+     */
+    public void delete()
+    {
+        context.getApi().getAdminApi().deleteRole(target);
+        target = null;
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Roles+Resource#RolesResource-CreateanewRole">
+     *      http
+     *      ://community.abiquo.com/display/ABI20/Roles+Resource#RolesResource-CreateanewRole</a>
+     */
+    public void save()
+    {
+        target = context.getApi().getAdminApi().createRole(target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Roles+Resource#RolesResource-UpdateanexistingRole"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Roles+Resource#RolesResource-UpdateanexistingRole
+     *      </a>
+     */
+    public void update()
+    {
+        target = context.getApi().getAdminApi().updateRole(target);
+    }
+
+    public void setEnterprise(final Enterprise enterprise)
+    {
+        checkNotNull(enterprise, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+        checkNotNull(enterprise.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in "
+            + Enterprise.class);
+
+        RESTLink link = enterprise.unwrap().searchLink("edit");
+
+        checkNotNull(link, ValidationErrors.MISSING_REQUIRED_LINK);
+
+        target.addLink(new RESTLink("enterprise", link.getHref()));
+    }
+
+    @EnterpriseEdition
+    public void setPrivileges(final List<Privilege> privileges)
+    {
+        for (Privilege privilege : privileges)
+        {
+            addPrivilege(privilege);
+        }
+    }
+
+    @EnterpriseEdition
+    private void addPrivilege(final Privilege privilege)
+    {
+        checkNotNull(privilege, ValidationErrors.NULL_RESOURCE + Privilege.class);
+        checkNotNull(privilege.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in "
+            + Privilege.class);
+
+        RESTLink link = privilege.unwrap().searchLink("self");
+
+        // rel would be "privilege" if the object is coming from a privilege list.
+        if (link == null)
+        {
+            link = privilege.unwrap().searchLink("privilege");
+        }
+
+        checkNotNull(link, ValidationErrors.MISSING_REQUIRED_LINK);
+
+        target.addLink(new RESTLink("privilege" + privilege.getId(), link.getHref()));
+    }
+
+    // Children access
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Roles+Resource#RolesResource-RetrievealistofprivilegesfromaRole"
+     *      > http://community.abiquo.com/display/ABI20/Roles+Resource#RolesResource-
+     *      RetrievealistofprivilegesfromaRole</a>
+     */
+    public List<Privilege> listPrivileges()
+    {
+        PrivilegesDto dto = context.getApi().getAdminApi().listPrivileges(target);
+
+        return wrap(context, Privilege.class, dto.getCollection());
+    }
+
+    public List<Privilege> listPrivileges(final Predicate<Privilege> filter)
+    {
+        return Lists.newLinkedList(filter(listPrivileges(), filter));
+    }
+
+    public Privilege findPrivileges(final Predicate<Privilege> filter)
+    {
+        return Iterables.getFirst(filter(listPrivileges(), filter), null);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        return new Builder(context);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name;
+
+        private boolean blocked = DEFAULT_BLOCKED;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+        {
+            super();
+            this.context = context;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder blocked(final boolean blocked)
+        {
+            this.blocked = blocked;
+            return this;
+        }
+
+        public Role build()
+        {
+            RoleDto dto = new RoleDto();
+            dto.setName(name);
+            dto.setBlocked(blocked);
+            Role role = new Role(context, dto);
+
+            return role;
+        }
+
+        public static Builder fromRole(final Role in)
+        {
+            return Role.builder(in.context).blocked(in.isBlocked()).name(in.getName());
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public boolean isBlocked()
+    {
+        return target.isBlocked();
+    }
+
+    public void setBlocked(final boolean blocked)
+    {
+        target.setBlocked(blocked);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Role [id=" + getId() + ", name=" + getName() + ", blocked=" + isBlocked() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/TemplateDefinitionList.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/TemplateDefinitionList.java
new file mode 100644
index 0000000..f4e9b13
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/TemplateDefinitionList.java
@@ -0,0 +1,236 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.am.model.TemplatesStateDto;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link TemplateDefinitionListDto}. A Template Definition List
+ * provides a way to organize multiple Template Definitions. A single Template Definition can be
+ * shared by many lists. Its compatible with ovfindex.xml format.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class TemplateDefinitionList extends DomainWrapper<TemplateDefinitionListDto>
+{
+    /** The enterprise where the list belongs. */
+    private Enterprise enterprise;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected TemplateDefinitionList(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final TemplateDefinitionListDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Delete the template definition list. Deleting the list doesn't delete the containing Template
+     * Definitions.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Deleteatemplatedefinitionlist"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Deleteatemplatedefinitionlist</a>
+     */
+    public void delete()
+    {
+        context.getApi().getEnterpriseApi().deleteTemplateDefinitionList(target);
+        target = null;
+    }
+
+    /**
+     * Create a template definition list. All the contained Template Definitions will also be
+     * created.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Createatemplatedefinitionlist"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Createatemplatedefinitionlistr</a>
+     */
+    public void save()
+    {
+        target =
+            context.getApi().getEnterpriseApi()
+                .createTemplateDefinitionList(enterprise.unwrap(), target);
+    }
+
+    /**
+     * Update a template definition list with the data from this template definition list.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Modifyatemplatedefinitionlist"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Modifyatemplatedefinitionlist</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getEnterpriseApi().updateTemplateDefinitionList(target);
+    }
+
+    // Children access
+
+    /**
+     * Retrieve the list of states of the templates in the template definition list in the
+     * repository of the given datacenter. Template Definition are available sources, but in order
+     * to create a Virtual Machine the Definition should be downloaded into the Datacenter
+     * Repository (NFS filesystem).
+     * 
+     * @param The datacenter in which repository search.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Retrievealistofthestatusofalltemplatestatuslist"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Retrievealistofthestatusofalltemplatestatuslist</a>
+     */
+    public List<TemplateState> listStatus(final Datacenter datacenter)
+    {
+        TemplatesStateDto states =
+            context.getApi().getEnterpriseApi()
+                .listTemplateListStatus(target, datacenter.unwrap());
+        return wrap(context, TemplateState.class, states.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of states of the templates in the template definition list in the
+     * repository of the given datacenter. Template Definition are available sources, but in order
+     * to create a Virtual Machine the Definition should be downloaded into the Datacenter
+     * Repository (NFS filesystem).
+     * 
+     * @param filter Filter to be applied to the list.
+     * @param The datacenter in which repository search.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#TemplateDefinitionListResource-Retrievealistofthestatusofalltemplatestatuslist"
+     *      > http://community.abiquo.com/display/ABI20/TemplateDefinitionListResource#
+     *      TemplateDefinitionListResource-Retrievealistofthestatusofalltemplatestatuslist</a>
+     */
+    public List<TemplateState> listStatus(final Predicate<TemplateState> filter,
+        final Datacenter datacenter)
+    {
+        return Lists.newLinkedList(filter(listStatus(datacenter), filter));
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Enterprise enterprise)
+    {
+        return new Builder(context, enterprise);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private Enterprise enterprise;
+
+        private String name;
+
+        private String url;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Enterprise enterprise)
+        {
+            super();
+            this.context = context;
+            this.enterprise = enterprise;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder url(final String url)
+        {
+            this.url = url;
+            return this;
+        }
+
+        public TemplateDefinitionList build()
+        {
+            TemplateDefinitionListDto dto = new TemplateDefinitionListDto();
+            dto.setName(name);
+            dto.setUrl(url);
+
+            TemplateDefinitionList templateList = new TemplateDefinitionList(context, dto);
+            templateList.enterprise = enterprise;
+            return templateList;
+
+        }
+
+        public static Builder fromTemplateDefinitionList(final TemplateDefinitionList in)
+        {
+            return TemplateDefinitionList.builder(in.context, in.enterprise).name(in.getName())
+                .url(in.getUrl());
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getUrl()
+    {
+        return target.getUrl();
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setUrl(final String url)
+    {
+        target.setUrl(url);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "TemplateDefinitionList [getId()=" + getId() + ", getName()=" + getName()
+            + ", getUrl()=" + getUrl() + "]";
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/TemplateState.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/TemplateState.java
new file mode 100644
index 0000000..c0773b8
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/TemplateState.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.am.model.TemplateStateDto;
+import com.abiquo.am.model.TemplateStatusEnumType;
+
+/**
+ * Adds high level functionality to {@link TemplateStateDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class TemplateState extends DomainWrapper<TemplateStateDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected TemplateState(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final TemplateStateDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    public Double getDownloadingProgress()
+    {
+        return target.getDownloadingProgress();
+    }
+
+    public String getErrorCause()
+    {
+        return target.getErrorCause();
+    }
+
+    public String getMasterOvf()
+    {
+        return target.getMasterOvf();
+    }
+
+    public String getOvfId()
+    {
+        return target.getOvfId();
+    }
+
+    public TemplateStatusEnumType getStatus()
+    {
+        return target.getStatus();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "TemplateState [getDownloadingProgress()=" + getDownloadingProgress()
+            + ", getErrorCause()=" + getErrorCause() + ", getMasterOvf()=" + getMasterOvf()
+            + ", getOvfId()=" + getOvfId() + ", getStatus()=" + getStatus() + "]";
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/User.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/User.java
new file mode 100644
index 0000000..bfb1b6c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/User.java
@@ -0,0 +1,509 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualDatacenters;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.RoleDto;
+import com.abiquo.server.core.enterprise.UserDto;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link UserDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Users+Resource">
+ *      http://community.abiquo.com/display/ABI20/Users+Resource</a>
+ */
+public class User extends DomainWrapper<UserDto>
+{
+    /** Default active value of the user */
+    private static final boolean DEFAULT_ACTIVE = true;
+
+    /** The default authentication type. */
+    private static final String DEFAULT_AUTH_TYPE = "ABIQUO";
+
+    /** The default locale for the user. */
+    private static final String DEFAULT_LOCALE = "en_US";
+
+    /** The enterprise where the user belongs. */
+    private Enterprise enterprise;
+
+    /** Role of the user. */
+    private Role role;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected User(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final UserDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/User+resource#Userresource-Deleteanexistinguser"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/User+resource#Userresource-Deleteanexistinguser
+     *      </a>
+     */
+    public void delete()
+    {
+        context.getApi().getEnterpriseApi().deleteUser(target);
+        target = null;
+    }
+
+    /**
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/User+resource#Userresource-Createanewuser"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/User+resource#Userresource-Createanewuser</a>
+     */
+    public void save()
+    {
+        // set role link
+        target.addLink(new RESTLink("role", role.unwrap().getEditLink().getHref()));
+        target = context.getApi().getEnterpriseApi().createUser(enterprise.unwrap(), target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/User+resource#Userresource-Updatesanexistinguser"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/User+resource#Userresource-Updatesanexistinguser
+     *      </a>
+     */
+    public void update()
+    {
+        // update role link (if exists)
+        if (role != null)
+        {
+            target.searchLink("role").setHref(role.unwrap().getEditLink().getHref());
+        }
+
+        target = context.getApi().getEnterpriseApi().updateUser(target);
+    }
+
+    public List<VirtualDatacenter> listPermitedVirtualDatacenters()
+    {
+        List<Integer> ids = extractAvailableDatacenters();
+
+        // null value means all virtual datacenters all allowed
+        if (ids.size() == 0)
+        {
+            return this.getEnterprise().listVirtualDatacenters();
+        }
+
+        ListVirtualDatacenters listVirtualDatacenters =
+            context.getUtils().getInjector().getInstance(ListVirtualDatacenters.class);
+        return Lists.newArrayList(listVirtualDatacenters.execute(ids));
+    }
+
+    public List<VirtualDatacenter> listPermitedVirtualDatacenters(
+        final Predicate<VirtualDatacenter> filter)
+    {
+        return Lists.newLinkedList(filter(listPermitedVirtualDatacenters(), filter));
+    }
+
+    public VirtualDatacenter findPermitedVirtualDatacenter(final Predicate<VirtualDatacenter> filter)
+    {
+        return Iterables.getFirst(filter(listPermitedVirtualDatacenters(), filter), null);
+    }
+
+    /**
+     * Give access to all virtualdatacenters in the enterprise (requires update).
+     */
+    public void permitAllVirtualDatacenters()
+    {
+        setAvailableVirtualDatacenters(null);
+    }
+
+    /**
+     * Limits user access ONLY to the virtual datacenters in the list. If the list is empty, user
+     * will get access to all virtual datacenters.
+     * 
+     * @param vdc List of virtual datancers from the user's enterprise.
+     */
+    public void setPermitedVirtualDatacenters(final List<VirtualDatacenter> vdcs)
+    {
+        List<Integer> ids = new ArrayList<Integer>();
+
+        for (VirtualDatacenter vdc : vdcs)
+        {
+            checkNotNull(vdc.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in "
+                + VirtualDatacenter.class);
+            ids.add(vdc.getId());
+        }
+
+        setAvailableVirtualDatacenters(ids);
+    }
+
+    // Parent access
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-RetrieveaEnterprise"
+     *      > http://community.abiquo.com/display/ABI20/Enterprise+Resource#EnterpriseResource-
+     *      RetrieveaEnterprise</a>
+     */
+    public Enterprise getEnterprise()
+    {
+        Integer enterpriseId = target.getIdFromLink(ParentLinkName.ENTERPRISE);
+        return wrap(context, Enterprise.class, context.getApi().getEnterpriseApi()
+            .getEnterprise(enterpriseId));
+    }
+
+    // Children access
+
+    public Role getRole()
+    {
+        RoleDto role = context.getApi().getAdminApi().getRole(target);
+        return wrap(context, Role.class, role);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/User+resource#Userresource-Retrievethelistofvirtualmachinesbyuser"
+     *      > http://community.abiquo.com/display/ABI20/User+resource#Userresource-
+     *      Retrievethelistofvirtualmachinesbyuser</a>
+     */
+    public List<VirtualMachine> listMachines()
+    {
+        VirtualMachinesWithNodeExtendedDto machines =
+            context.getApi().getEnterpriseApi().listVirtualMachines(target);
+        return wrap(context, VirtualMachine.class, machines.getCollection());
+    }
+
+    public List<VirtualMachine> listMachines(final Predicate<VirtualMachine> filter)
+    {
+        return Lists.newLinkedList(filter(listMachines(), filter));
+    }
+
+    public VirtualMachine findMachine(final Predicate<VirtualMachine> filter)
+    {
+        return Iterables.getFirst(filter(listMachines(), filter), null);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Enterprise enterprise, final Role role)
+    {
+        return new Builder(context, enterprise, role);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private Enterprise enterprise;
+
+        private Role role;
+
+        private String name;
+
+        private String nick;
+
+        private String locale = DEFAULT_LOCALE;
+
+        private String password;
+
+        private String surname;
+
+        private boolean active = DEFAULT_ACTIVE;
+
+        private String email;
+
+        private String description;
+
+        private String authType = DEFAULT_AUTH_TYPE;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Enterprise enterprise, final Role role)
+        {
+            super();
+            checkNotNull(enterprise, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+            checkNotNull(role, ValidationErrors.NULL_RESOURCE + Role.class);
+            this.context = context;
+            this.enterprise = enterprise;
+            this.role = role;
+        }
+
+        public Builder enterprise(final Enterprise enterprise)
+        {
+            checkNotNull(enterprise, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+            this.enterprise = enterprise;
+            return this;
+        }
+
+        public Builder role(final Role role)
+        {
+            this.role = role;
+            return this;
+        }
+
+        public Builder name(final String name, final String surname)
+        {
+            this.name = name;
+            this.surname = surname;
+            return this;
+        }
+
+        public Builder nick(final String nick)
+        {
+            this.nick = nick;
+            return this;
+        }
+
+        public Builder locale(final String locale)
+        {
+            this.locale = locale;
+            return this;
+        }
+
+        public Builder password(final String password)
+        {
+            this.password = password;
+            return this;
+        }
+
+        public Builder active(final boolean active)
+        {
+            this.active = active;
+            return this;
+        }
+
+        public Builder email(final String email)
+        {
+            this.email = email;
+            return this;
+        }
+
+        public Builder description(final String description)
+        {
+            this.description = description;
+            return this;
+        }
+
+        public Builder authType(final String authType)
+        {
+            this.authType = authType;
+            return this;
+        }
+
+        public User build()
+        {
+            UserDto dto = new UserDto();
+            dto.setActive(active);
+            dto.setAuthType(authType);
+            dto.setDescription(description);
+            dto.setEmail(email);
+            dto.setLocale(locale);
+            dto.setName(name);
+            dto.setNick(nick);
+            dto.setPassword(password);
+            dto.setSurname(surname);
+            User user = new User(context, dto);
+            user.enterprise = enterprise;
+            user.role = role;
+
+            return user;
+        }
+
+        public static Builder fromUser(final User in)
+        {
+            return User.builder(in.context, in.enterprise, in.role).active(in.isActive())
+                .authType(in.getAuthType()).description(in.getDescription()).email(in.getEmail())
+                .locale(in.getLocale()).name(in.getName(), in.getSurname()).nick(in.getNick())
+                .password(in.getPassword());
+        }
+    }
+
+    // Delegate methods
+
+    public String getAuthType()
+    {
+        return target.getAuthType();
+    }
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    public String getEmail()
+    {
+        return target.getEmail();
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getLocale()
+    {
+        return target.getLocale();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getNick()
+    {
+        return target.getNick();
+    }
+
+    public String getPassword()
+    {
+        return target.getPassword();
+    }
+
+    public String getSurname()
+    {
+        return target.getSurname();
+    }
+
+    public boolean isActive()
+    {
+        return target.isActive();
+    }
+
+    public void setActive(final boolean active)
+    {
+        target.setActive(active);
+    }
+
+    public void setAuthType(final String authType)
+    {
+        target.setAuthType(authType);
+    }
+
+    public void setDescription(final String description)
+    {
+        target.setDescription(description);
+    }
+
+    public void setEmail(final String email)
+    {
+        target.setEmail(email);
+    }
+
+    public void setLocale(final String locale)
+    {
+        target.setLocale(locale);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setNick(final String nick)
+    {
+        target.setNick(nick);
+    }
+
+    public void setPassword(final String password)
+    {
+        target.setPassword(password);
+    }
+
+    public void setSurname(final String surname)
+    {
+        target.setSurname(surname);
+    }
+
+    public void setRole(final Role role)
+    {
+        this.role = role;
+    }
+
+    // Aux operations
+
+    /**
+     * Converts the tokenized String of available virtual datacenters provided in the userDto to a
+     * list of ids.
+     */
+    private List<Integer> extractAvailableDatacenters()
+    {
+        List<Integer> ids = Lists.newArrayList();
+
+        if (target.getAvailableVirtualDatacenters() != null)
+        {
+
+            StringTokenizer st = new StringTokenizer(target.getAvailableVirtualDatacenters(), ",");
+
+            while (st.hasMoreTokens())
+            {
+                ids.add(Integer.parseInt(st.nextToken()));
+            }
+        }
+
+        return ids;
+    }
+
+    private void setAvailableVirtualDatacenters(final List<Integer> ids)
+    {
+        if (ids == null || ids.size() == 0)
+        {
+            target.setAvailableVirtualDatacenters("");
+        }
+        else
+        {
+            Joiner joiner = Joiner.on(",").skipNulls();
+            target.setAvailableVirtualDatacenters(joiner.join(ids));
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return "User [id=" + getId() + ", role=" + getRole() + ", authType=" + getAuthType()
+            + ", description=" + getDescription() + ", email=" + getEmail() + ", locale="
+            + getLocale() + ", name=" + getName() + ", nick=" + getNick() + ", password="
+            + getPassword() + ", surname=" + getSurname() + ", active=" + isActive() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/options/EnterpriseOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/options/EnterpriseOptions.java
new file mode 100644
index 0000000..fb5bfdb
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/enterprise/options/EnterpriseOptions.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise.options;
+
+import org.jclouds.abiquo.domain.options.search.FilterOptions.BaseFilterOptionsBuilder;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query enterprises.
+ * 
+ * @author Francesc Montserrat
+ */
+public class EnterpriseOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        EnterpriseOptions options = new EnterpriseOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder extends BaseFilterOptionsBuilder<Builder>
+    {
+        private String idPricingTemplate;
+
+        private Boolean included;
+
+        private String filter;
+
+        private Integer page;
+
+        private Integer results;
+
+        private Boolean network;
+
+        public Builder pricingTemplate(final String idPricingTemplate)
+        {
+            this.idPricingTemplate = idPricingTemplate;
+            return this;
+        }
+
+        public Builder included(final boolean included)
+        {
+            this.included = included;
+            return this;
+        }
+
+        public Builder filter(final String filter)
+        {
+            this.filter = filter;
+            return this;
+        }
+
+        public Builder network(final boolean network)
+        {
+            this.network = network;
+            return this;
+        }
+
+        public Builder page(final int page)
+        {
+            this.page = page;
+            return this;
+        }
+
+        public Builder results(final int results)
+        {
+            this.results = results;
+            return this;
+        }
+
+        public EnterpriseOptions build()
+        {
+            EnterpriseOptions options = new EnterpriseOptions();
+
+            if (idPricingTemplate != null)
+            {
+                options.queryParameters.put("idPricingTemplate", String.valueOf(idPricingTemplate));
+            }
+
+            if (included != null)
+            {
+                options.queryParameters.put("included", String.valueOf(included));
+            }
+
+            if (filter != null)
+            {
+                options.queryParameters.put("filter", String.valueOf(filter));
+            }
+
+            if (page != null)
+            {
+                options.queryParameters.put("page", String.valueOf(page));
+            }
+
+            if (results != null)
+            {
+                options.queryParameters.put("numResults", String.valueOf(results));
+            }
+
+            if (network != null)
+            {
+                options.queryParameters.put("network", String.valueOf(network));
+            }
+
+            return addFilterOptions(options);
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/event/Event.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/event/Event.java
new file mode 100644
index 0000000..5bb0791
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/event/Event.java
@@ -0,0 +1,393 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.event;
+
+import java.util.Date;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.SeverityType;
+import com.abiquo.server.core.event.EventDto;
+
+/**
+ * @author Vivien Mahé
+ */
+public class Event extends DomainWrapper<EventDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Event(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final EventDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getUser()
+    {
+        return target.getUser();
+    }
+
+    public void setUser(final String user)
+    {
+        target.setUser(user);
+    }
+
+    public String getStacktrace()
+    {
+        return target.getStacktrace();
+    }
+
+    public void setStacktrace(final String stacktrace)
+    {
+        target.setStacktrace(stacktrace);
+    }
+
+    public String getComponent()
+    {
+        return target.getComponent();
+    }
+
+    public void setComponent(final String component)
+    {
+        target.setComponent(component);
+    }
+
+    public String getPerformedBy()
+    {
+        return target.getPerformedBy();
+    }
+
+    public void setPerformedBy(final String performedBy)
+    {
+        target.setPerformedBy(performedBy);
+    }
+
+    public Integer getIdNetwork()
+    {
+        return target.getIdNetwork();
+    }
+
+    public void setIdNetwork(final Integer idNetwork)
+    {
+        target.setIdNetwork(idNetwork);
+    }
+
+    public String getIdVolume()
+    {
+        return target.getIdVolume();
+    }
+
+    public void setIdVolume(final String idVolume)
+    {
+        target.setIdVolume(idVolume);
+    }
+
+    public String getStoragePool()
+    {
+        return target.getStoragePool();
+    }
+
+    public void setStoragePool(final String storagePool)
+    {
+        target.setStoragePool(storagePool);
+    }
+
+    public Date getTimestamp()
+    {
+        return target.getTimestamp();
+    }
+
+    public void setTimestamp(final Date timestamp)
+    {
+        target.setTimestamp(timestamp);
+    }
+
+    public String getVirtualApp()
+    {
+        return target.getVirtualApp();
+    }
+
+    public void setVirtualApp(final String virtualApp)
+    {
+        target.setVirtualApp(virtualApp);
+    }
+
+    public String getDatacenter()
+    {
+        return target.getDatacenter();
+    }
+
+    public void setDatacenter(final String datacenter)
+    {
+        target.setDatacenter(datacenter);
+    }
+
+    public String getActionPerformed()
+    {
+        return target.getActionPerformed();
+    }
+
+    public void setActionPerformed(final String actionPerformed)
+    {
+        target.setActionPerformed(actionPerformed);
+    }
+
+    public Integer getIdVirtualMachine()
+    {
+        return target.getIdVirtualMachine();
+    }
+
+    public void setIdVirtualMachine(final Integer idVirtualMachine)
+    {
+        target.setIdVirtualMachine(idVirtualMachine);
+    }
+
+    public String getVirtualDatacenter()
+    {
+        return target.getVirtualDatacenter();
+    }
+
+    public void setVirtualDatacenter(final String virtualDatacenter)
+    {
+        target.setVirtualDatacenter(virtualDatacenter);
+    }
+
+    public String getEnterprise()
+    {
+        return target.getEnterprise();
+    }
+
+    public void setEnterprise(final String enterprise)
+    {
+        target.setEnterprise(enterprise);
+    }
+
+    public String getStorageSystem()
+    {
+        return target.getStorageSystem();
+    }
+
+    public void setStorageSystem(final String storageSystem)
+    {
+        target.setStorageSystem(storageSystem);
+    }
+
+    public Integer getIdPhysicalMachine()
+    {
+        return target.getIdPhysicalMachine();
+    }
+
+    public void setIdPhysicalMachine(final Integer idPhysicalMachine)
+    {
+        target.setIdPhysicalMachine(idPhysicalMachine);
+    }
+
+    public SeverityType getSeverity()
+    {
+        return target.getSeverity();
+    }
+
+    public void setSeverity(final SeverityType severity)
+    {
+        target.setSeverity(severity);
+    }
+
+    public Integer getIdStorageSystem()
+    {
+        return target.getIdStorageSystem();
+    }
+
+    public void setIdStorageSystem(final Integer idStorageSystem)
+    {
+        target.setIdStorageSystem(idStorageSystem);
+    }
+
+    public Integer getIdDatacenter()
+    {
+        return target.getIdDatacenter();
+    }
+
+    public void setIdDatacenter(final Integer idDatacenter)
+    {
+        target.setIdDatacenter(idDatacenter);
+    }
+
+    public String getNetwork()
+    {
+        return target.getNetwork();
+    }
+
+    public void setNetwork(final String network)
+    {
+        target.setNetwork(network);
+    }
+
+    public String getPhysicalMachine()
+    {
+        return target.getPhysicalMachine();
+    }
+
+    public void setPhysicalMachine(final String physicalMachine)
+    {
+        target.setPhysicalMachine(physicalMachine);
+    }
+
+    public String getRack()
+    {
+        return target.getRack();
+    }
+
+    public void setRack(final String rack)
+    {
+        target.setRack(rack);
+    }
+
+    public Integer getIdVirtualDatacenter()
+    {
+        return target.getIdVirtualDatacenter();
+    }
+
+    public void setIdVirtualDatacenter(final Integer idVirtualDatacenter)
+    {
+        target.setIdVirtualDatacenter(idVirtualDatacenter);
+    }
+
+    public Integer getIdSubnet()
+    {
+        return target.getIdSubnet();
+    }
+
+    public void setIdSubnet(final Integer idSubnet)
+    {
+        target.setIdSubnet(idSubnet);
+    }
+
+    public String getVolume()
+    {
+        return target.getVolume();
+    }
+
+    public void setVolume(final String volume)
+    {
+        target.setVolume(volume);
+    }
+
+    public String getSubnet()
+    {
+        return target.getSubnet();
+    }
+
+    public void setSubnet(final String subnet)
+    {
+        target.setSubnet(subnet);
+    }
+
+    public Integer getIdUser()
+    {
+        return target.getIdUser();
+    }
+
+    public void setIdUser(final Integer idUser)
+    {
+        target.setIdUser(idUser);
+    }
+
+    public String getIdStoragePool()
+    {
+        return target.getIdStoragePool();
+    }
+
+    public void setIdStoragePool(final String idStoragePool)
+    {
+        target.setIdStoragePool(idStoragePool);
+    }
+
+    public Integer getIdRack()
+    {
+        return target.getIdRack();
+    }
+
+    public void setIdRack(final Integer idRack)
+    {
+        target.setIdRack(idRack);
+    }
+
+    public String getVirtualMachine()
+    {
+        return target.getVirtualMachine();
+    }
+
+    public void setVirtualMachine(final String virtualMachine)
+    {
+        target.setVirtualMachine(virtualMachine);
+    }
+
+    public Integer getIdVirtualApp()
+    {
+        return target.getIdVirtualApp();
+    }
+
+    public void setIdVirtualApp(final Integer idVirtualApp)
+    {
+        target.setIdVirtualApp(idVirtualApp);
+    }
+
+    public Integer getIdEnterprise()
+    {
+        return target.getIdEnterprise();
+    }
+
+    public void setIdEnterprise(final Integer idEnterprise)
+    {
+        target.setIdEnterprise(idEnterprise);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Event [id=" + getId() + ", idUser=" + getIdUser() + ", user=" + getUser()
+            + ", idEnterprise=" + getIdEnterprise() + ", enterprise=" + getEnterprise()
+            + ", actionPerformed=" + getActionPerformed() + ", component=" + getComponent()
+            + ", idDatacenter=" + getIdDatacenter() + ", datacenter=" + getDatacenter()
+            + ", idStoragePool=" + getIdStoragePool() + ", storagePool=" + getStoragePool()
+            + ", idVolume=" + getIdVolume() + ", volume=" + getVolume() + ", idNetwork="
+            + getIdNetwork() + ", network=" + getNetwork() + ", idPhysicalMachine="
+            + getIdPhysicalMachine() + ", physicalMachine=" + getPhysicalMachine() + ", idRack="
+            + getIdRack() + ", rack=" + getRack() + ", idStorageSystem=" + getIdStorageSystem()
+            + ", storageSystem=" + getStorageSystem() + ", idSubnet=" + getIdSubnet() + ", subnet="
+            + getSubnet() + ", idVirtualApp=" + getIdVirtualApp() + ", virtualApp="
+            + getVirtualApp() + ", idVirtualDatacenter=" + getIdVirtualDatacenter()
+            + ", virtualDatacenter=" + getVirtualDatacenter() + ", idVirtualMachine="
+            + getIdVirtualMachine() + ", virtualMachine=" + getVirtualMachine() + ", stackstrace="
+            + getStacktrace() + ", performedBy=" + getPerformedBy() + ", severity=" + getSeverity()
+            + "]";
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/event/options/EventOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/event/options/EventOptions.java
new file mode 100644
index 0000000..1a606d9
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/event/options/EventOptions.java
@@ -0,0 +1,196 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.event.options;
+
+import java.util.Date;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.jclouds.abiquo.domain.options.search.FilterOptions.BaseFilterOptionsBuilder;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.abiquo.model.enumerator.ComponentType;
+import com.abiquo.model.enumerator.EventType;
+import com.abiquo.model.enumerator.SeverityType;
+import com.google.common.collect.Maps;
+
+/**
+ * Available options to query events.
+ * 
+ * @author Vivien Mahé
+ */
+public class EventOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        EventOptions options = new EventOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder extends BaseFilterOptionsBuilder<Builder>
+    {
+        private Map<String, String> filters = Maps.newHashMap();
+
+        public Builder filters(final Map<String, String> filters)
+        {
+            this.filters = filters;
+            return this;
+        }
+
+        public Builder severity(final SeverityType severity)
+        {
+            this.filters.put("severity", severity.name());
+            return this;
+        }
+
+        public Builder component(final ComponentType component)
+        {
+            this.filters.put("component", component.name());
+            return this;
+        }
+
+        public Builder actionPerformed(final EventType action)
+        {
+            this.filters.put("actionperformed", action.name());
+            return this;
+        }
+
+        public Builder datacenterName(final String dc)
+        {
+            this.filters.put("datacenter", dc);
+            return this;
+        }
+
+        public Builder rackName(final String rack)
+        {
+            this.filters.put("rack", rack);
+            return this;
+        }
+
+        public Builder physicalMachineName(final String pm)
+        {
+            this.filters.put("physicalmachine", pm);
+            return this;
+        }
+
+        public Builder storageSystemName(final String ss)
+        {
+            this.filters.put("storagesystem", ss);
+            return this;
+        }
+
+        public Builder storagePoolName(final String sp)
+        {
+            this.filters.put("storagepool", sp);
+            return this;
+        }
+
+        public Builder volumeName(final String volume)
+        {
+            this.filters.put("volume", volume);
+            return this;
+        }
+
+        public Builder networkName(final String network)
+        {
+            this.filters.put("network", network);
+            return this;
+        }
+
+        public Builder subnetName(final String subnet)
+        {
+            this.filters.put("subnet", subnet);
+            return this;
+        }
+
+        public Builder enterpriseName(final String ent)
+        {
+            this.filters.put("enterprise", ent);
+            return this;
+        }
+
+        public Builder userName(final String user)
+        {
+            this.filters.put("user", user);
+            return this;
+        }
+
+        public Builder virtualDatacenterName(final String vdc)
+        {
+            this.filters.put("virtualdatacenter", vdc);
+            return this;
+        }
+
+        public Builder virtualAppName(final String vapp)
+        {
+            this.filters.put("virtualapp", vapp);
+            return this;
+        }
+
+        public Builder virtualMachineName(final String vm)
+        {
+            this.filters.put("virtualMachine", vm);
+            return this;
+        }
+
+        public Builder performedBy(final String pb)
+        {
+            this.filters.put("performedBy", pb);
+            return this;
+        }
+
+        public Builder description(final String description)
+        {
+            this.filters.put("stacktrace", description);
+            return this;
+        }
+
+        public Builder dateFrom(final Date date)
+        {
+            this.filters.put("datefrom", String.valueOf(date.getTime()));
+            return this;
+        }
+
+        public Builder dateTo(final Date date)
+        {
+            this.filters.put("dateTo", String.valueOf(date.getTime()));
+            return this;
+        }
+
+        public EventOptions build()
+        {
+            EventOptions options = new EventOptions();
+
+            for (Entry<String, String> filter : filters.entrySet())
+            {
+                options.queryParameters.put(filter.getKey(), filter.getValue());
+            }
+
+            return addFilterOptions(options);
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/AbiquoException.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/AbiquoException.java
new file mode 100644
index 0000000..1a8ddf5
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/AbiquoException.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.exception;
+
+import static com.google.common.collect.Iterables.any;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.find;
+import static org.jclouds.abiquo.predicates.ErrorPredicates.code;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import com.abiquo.model.transport.error.ErrorDto;
+import com.abiquo.model.transport.error.ErrorsDto;
+import com.google.common.collect.Lists;
+
+/**
+ * Abiquo API exception.
+ * 
+ * @author Francesc Montserrat
+ * @author Ignasi Barrera
+ */
+public class AbiquoException extends RuntimeException
+{
+    /** Serial UID. */
+    private static final long serialVersionUID = 1L;
+
+    /** The HTTP statuc. */
+    private Status httpStatus;
+
+    /** The errors. */
+    private ErrorsDto errors;
+
+    public AbiquoException(final Status httpStatus, final ErrorsDto errors)
+    {
+        super();
+        this.httpStatus = httpStatus;
+        this.errors = errors;
+    }
+
+    /**
+     * Check if there is an error with the given code.
+     */
+    public boolean hasError(final String code)
+    {
+        return any(errors.getCollection(), code(code));
+    }
+
+    /**
+     * Find the first error with the given code.
+     */
+    public ErrorDto findError(final String code)
+    {
+        return find(errors.getCollection(), code(code), null);
+    }
+
+    /**
+     * Find all errors with the given code.
+     */
+    public List<ErrorDto> findErrors(final String code)
+    {
+        return Lists.newLinkedList(filter(errors.getCollection(), code(code)));
+    }
+
+    /**
+     * Get the number of errors.
+     */
+    public int numErrors()
+    {
+        return errors.getCollection().size();
+    }
+
+    /**
+     * Get the list of all errors.
+     */
+    public List<ErrorDto> getErrors()
+    {
+        return errors.getCollection();
+    }
+
+    /**
+     * Get the HTTP status code.
+     */
+    public int getHttpStatusCode()
+    {
+        return httpStatus.getStatusCode();
+    }
+
+    /**
+     * Get the HTTP status name.
+     */
+    public String getHttpStatusName()
+    {
+        return httpStatus.getReasonPhrase();
+    }
+
+    /**
+     * Get the HTTP status.
+     */
+    public Status getHttpStatus()
+    {
+        return httpStatus;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return errors.toString();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/BuilderException.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/BuilderException.java
new file mode 100644
index 0000000..850bb21
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/BuilderException.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.exception;
+
+/**
+ * Exception thrown during domain object building.
+ * 
+ * @author Ignasi Barrera
+ */
+public class BuilderException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Creates a {@link BuilderException} with the given message.
+     * 
+     * @param message The message.
+     */
+    public BuilderException(String message)
+    {
+        super(message);
+    }
+
+    /**
+     * Creates a {@link BuilderException} with the given cause.
+     * 
+     * @param cause The cause.
+     */
+    public BuilderException(Throwable cause)
+    {
+        super(cause);
+    }
+
+    /**
+     * Creates a {@link BuilderException} with the given message and cause.
+     * 
+     * @param message The message.
+     * @param cause The cause.
+     */
+    public BuilderException(String message, Throwable cause)
+    {
+        super(message, cause);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/WrapperException.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/WrapperException.java
new file mode 100644
index 0000000..40f9e8e
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/exception/WrapperException.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.exception;
+
+import org.jclouds.abiquo.domain.DomainWrapper;
+
+import com.abiquo.model.transport.SingleResourceTransportDto;
+
+/**
+ * Exception thrown during the wrapping process.
+ * 
+ * @author Ignasi Barrera
+ */
+public class WrapperException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    private Class< ? extends DomainWrapper< ? >> wrapperClass;
+
+    private SingleResourceTransportDto target;
+
+    public WrapperException(final Class< ? extends DomainWrapper< ? >> wrapperClass,
+        final SingleResourceTransportDto target, Throwable cause)
+    {
+        super(cause);
+        this.wrapperClass = wrapperClass;
+        this.target = target;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        String msg =
+            "Could not wrap object [" + target + "] in class " + wrapperClass.getName() + ": ";
+        return msg + super.getMessage();
+    }
+
+    public Class< ? extends DomainWrapper< ? >> getWrapperClass()
+    {
+        return wrapperClass;
+    }
+
+    public void setWrapperClass(Class< ? extends DomainWrapper< ? >> wrapperClass)
+    {
+        this.wrapperClass = wrapperClass;
+    }
+
+    public SingleResourceTransportDto getTarget()
+    {
+        return target;
+    }
+
+    public void setTarget(SingleResourceTransportDto target)
+    {
+        this.target = target;
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/AbstractPhysicalMachine.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/AbstractPhysicalMachine.java
new file mode 100644
index 0000000..6ec6c47
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/AbstractPhysicalMachine.java
@@ -0,0 +1,356 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.collect.Iterables.find;
+
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.predicates.infrastructure.DatastorePredicates;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.MachineIpmiState;
+import com.abiquo.model.enumerator.MachineState;
+import com.abiquo.server.core.infrastructure.DatastoresDto;
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.MachineIpmiStateDto;
+import com.abiquo.server.core.infrastructure.MachineStateDto;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link MachineDto}. This class defines common methods for
+ * unmanaged {@link Machine} and managed {@link Blade} physical machines.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/MachineResource">
+ *      http://community.abiquo.com/display/ABI20/MachineResource</a>
+ */
+public abstract class AbstractPhysicalMachine extends DomainWrapper<MachineDto>
+{
+    /** The default virtual ram used in MB. */
+    protected static final int DEFAULT_VRAM_USED = 1;
+
+    /** The default virtual cpu used in MB. */
+    protected static final int DEFAULT_VCPU_USED = 1;
+
+    /** List of available virtual switches provided by discover operation **/
+    protected List<String> virtualSwitches;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected AbstractPhysicalMachine(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final MachineDto target)
+    {
+        super(context, target);
+        extractVirtualSwitches();
+    }
+
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteMachine(target);
+        target = null;
+    }
+
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateMachine(target);
+    }
+
+    public MachineState check()
+    {
+        MachineStateDto dto =
+            context.getApi().getInfrastructureApi().checkMachineState(target, true);
+        MachineState state = dto.getState();
+        target.setState(state);
+        return state;
+    }
+
+    public MachineIpmiState checkIpmi()
+    {
+        MachineIpmiStateDto dto =
+            context.getApi().getInfrastructureApi().checkMachineIpmiState(target);
+        return dto.getState();
+    }
+
+    // Children access
+
+    public List<Datastore> getDatastores()
+    {
+        return wrap(context, Datastore.class, target.getDatastores().getCollection());
+    }
+
+    public Datastore findDatastore(final String name)
+    {
+        return find(getDatastores(), DatastorePredicates.name(name), null);
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getIp()
+    {
+        return target.getIp();
+    }
+
+    public String getIpmiIp()
+    {
+        return target.getIpmiIP();
+    }
+
+    public String getIpmiPassword()
+    {
+        return target.getIpmiPassword();
+    }
+
+    public Integer getIpmiPort()
+    {
+        return target.getIpmiPort();
+    }
+
+    public String getIpmiUser()
+    {
+        return target.getIpmiUser();
+    }
+
+    public String getIpService()
+    {
+        return target.getIpService();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getPassword()
+    {
+        return target.getPassword();
+    }
+
+    public Integer getPort()
+    {
+        return target.getPort();
+    }
+
+    public MachineState getState()
+    {
+        return target.getState();
+    }
+
+    public HypervisorType getType()
+    {
+        return target.getType();
+    }
+
+    public String getUser()
+    {
+        return target.getUser();
+    }
+
+    public Integer getVirtualCpuCores()
+    {
+        return target.getVirtualCpuCores();
+    }
+
+    public Integer getVirtualCpusUsed()
+    {
+        return target.getVirtualCpusUsed();
+    }
+
+    public Integer getVirtualRamInMb()
+    {
+        return target.getVirtualRamInMb();
+    }
+
+    public Integer getVirtualRamUsedInMb()
+    {
+        return target.getVirtualRamUsedInMb();
+    }
+
+    public String getVirtualSwitch()
+    {
+        return target.getVirtualSwitch();
+    }
+
+    public void setDatastores(final List<Datastore> datastores)
+    {
+        DatastoresDto datastoresDto = new DatastoresDto();
+        datastoresDto.getCollection().addAll(DomainWrapper.unwrap(datastores));
+        target.setDatastores(datastoresDto);
+    }
+
+    public void setDescription(final String description)
+    {
+        target.setDescription(description);
+    }
+
+    public void setIp(final String ip)
+    {
+        target.setIp(ip);
+    }
+
+    public void setIpmiIp(final String ipmiIp)
+    {
+        target.setIpmiIP(ipmiIp);
+    }
+
+    public void setIpmiPassword(final String ipmiPassword)
+    {
+        target.setIpmiPassword(ipmiPassword);
+    }
+
+    public void setIpmiPort(final Integer ipmiPort)
+    {
+        target.setIpmiPort(ipmiPort);
+    }
+
+    public void setIpmiUser(final String ipmiUser)
+    {
+        target.setIpmiUser(ipmiUser);
+    }
+
+    public void setIpService(final String ipService)
+    {
+        target.setIpService(ipService);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setPassword(final String password)
+    {
+        target.setPassword(password);
+    }
+
+    public void setPort(final Integer port)
+    {
+        target.setPort(port);
+    }
+
+    public void setState(final MachineState state)
+    {
+        target.setState(state);
+    }
+
+    public void setType(final HypervisorType type)
+    {
+        target.setType(type);
+    }
+
+    public void setUser(final String user)
+    {
+        target.setUser(user);
+    }
+
+    public void setVirtualCpuCores(final Integer virtualCpuCores)
+    {
+        target.setVirtualCpuCores(virtualCpuCores);
+    }
+
+    public void setVirtualCpusUsed(final Integer virtualCpusUsed)
+    {
+        target.setVirtualCpusUsed(virtualCpusUsed);
+    }
+
+    public void setVirtualRamInMb(final Integer virtualRamInMb)
+    {
+        target.setVirtualRamInMb(virtualRamInMb);
+    }
+
+    public void setVirtualRamUsedInMb(final Integer virtualRamUsedInMb)
+    {
+        target.setVirtualRamUsedInMb(virtualRamUsedInMb);
+    }
+
+    public void setVirtualSwitch(final String virtualSwitch)
+    {
+        target.setVirtualSwitch(virtualSwitch);
+    }
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    // Aux operations
+
+    /**
+     * Converts the tokenized String provided by the node collector API to a list of Strings and
+     * stores it at the attribute switches.
+     */
+    protected void extractVirtualSwitches()
+    {
+        StringTokenizer st = new StringTokenizer(getVirtualSwitch(), "/");
+        this.virtualSwitches = Lists.newArrayList();
+
+        while (st.hasMoreTokens())
+        {
+            this.virtualSwitches.add(st.nextToken());
+        }
+
+        if (virtualSwitches.size() > 0)
+        {
+            this.setVirtualSwitch(virtualSwitches.get(0));
+        }
+    }
+
+    /**
+     * Returns the virtual switches available. One of them needs to be selected.
+     */
+    public List<String> getAvailableVirtualSwitches()
+    {
+        return virtualSwitches;
+    }
+
+    public String findAvailableVirtualSwitch(final String vswitch)
+    {
+        return find(virtualSwitches, Predicates.equalTo(vswitch));
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Machine [id=" + getId() + ", ip=" + getIp() + ", ipmiIp=" + getIpmiIp()
+            + ", ipmiPassword=" + getIpmiPassword() + ", ipmiPort=" + getIpmiPort() + ", ipmiUser="
+            + getIpmiUser() + ", ipService=" + getIpService() + ", name=" + getName()
+            + ", password=" + getPassword() + ", port=" + getPort() + ", state=" + getState()
+            + ", type=" + getType() + ", user=" + getUser() + ", virtualCpuCores="
+            + getVirtualCpuCores() + ", virtualCpusUsed=" + getVirtualCpusUsed()
+            + ", getVirtualRamInMb()=" + getVirtualRamInMb() + ", virtualRamUsedInMb="
+            + getVirtualRamUsedInMb() + ", virtualSwitch=" + getVirtualSwitch() + ", description="
+            + getDescription() + ", availableVirtualSwitches=" + getAvailableVirtualSwitches()
+            + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Blade.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Blade.java
new file mode 100644
index 0000000..db2ca35
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Blade.java
@@ -0,0 +1,176 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.BladeLocatorLedDto;
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.UcsRackDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to a {@link MachineDto} managed in a UCS rack. This resource allows
+ * you to access blades in managed racks in the cloud infrastructure.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/MachineResource">
+ *      http://community.abiquo.com/display/ABI20/MachineResource</a>
+ */
+public class Blade extends AbstractPhysicalMachine
+{
+    /** The rack where the machine belongs. */
+    protected UcsRackDto rack;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Blade(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final MachineDto target)
+    {
+        super(context, target);
+    }
+
+    // Parent access
+
+    /**
+     * Retrieve the UCS rack where the blade is.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveaUCSRack" >
+     *      http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveaUCSRack</a>
+     */
+    public ManagedRack getRack()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.RACK),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.RACK);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<UcsRackDto> parser =
+            new ParseXMLWithJAXB<UcsRackDto>(utils.getXml(), TypeLiteral.get(UcsRackDto.class));
+
+        return wrap(context, ManagedRack.class, parser.apply(response));
+    }
+
+    /**
+     * Retrieve the logic server associated with this machine in the Cisco UCS rack.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrieveslogicserverassociatedwithamachineinaCiscoUCS"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      RetrieveslogicserverassociatedwithamachineinaCiscoUCS</a>
+     */
+    public LogicServer getLogicServer()
+    {
+        LogicServerDto server = context.getApi().getInfrastructureApi().getLogicServer(target);
+
+        return wrap(context, LogicServer.class, server);
+    }
+
+    // Actions
+
+    /**
+     * Turn the blade associated to the provided logic server off. The blade must belong to a Logic
+     * Server. This action sets the state of a given machine to STOPPED. Also sends a stop request
+     * to Cisco UCS to shut down the machine. The given machine must be a Physical Machine inside a
+     * Cisco UCS.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-PoweroffanexistingmachineinCiscoUCS"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      PoweroffanexistingmachineinCiscoUCS</a>
+     */
+    public void powerOff()
+    {
+        context.getApi().getInfrastructureApi().powerOff(target);
+    }
+
+    /**
+     * Turn the blade associated to the provided logic server on. The machine must belong to an UCS
+     * Rack. The blade must belong to a Logic Server.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-PoweronanexistingmachineinCiscoUCS"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      PoweronanexistingmachineinCiscoUCS</a>
+     */
+    public void powerOn()
+    {
+        context.getApi().getInfrastructureApi().powerOn(target);
+    }
+
+    /**
+     * Turn blade led on. The machine must belong to an UCS Rack. The blade must belong to a Logic
+     * Server.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-LightoffthelocatorledofanexistingmachineinaCiscoUCS"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      LightoffthelocatorledofanexistingmachineinaCiscoUCS</a>
+     */
+    public void ledOn()
+    {
+        context.getApi().getInfrastructureApi().ledOn(target);
+    }
+
+    /**
+     * Turn blade led off. The machine must belong to an UCS Rack. The blade must belong to a Logic
+     * Server.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource-LightoffthelocatorledofanexistingmachineinaCiscoUCS"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource-
+     *      LightoffthelocatorledofanexistingmachineinaCiscoUCS</a>
+     */
+    public void ledOff()
+    {
+        context.getApi().getInfrastructureApi().ledOff(target);
+    }
+
+    /**
+     * Retrieve the led locator information as a {@link BladeLocatorLed}.
+     * 
+     * @return Blade locator led representation.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-Retrievethelocatorledoftheblade"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      Retrievethelocatorledoftheblade</a>
+     */
+    public BladeLocatorLed getLocatorLed()
+    {
+        BladeLocatorLedDto led = context.getApi().getInfrastructureApi().getLocatorLed(target);
+
+        return wrap(context, BladeLocatorLed.class, led);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/BladeLocatorLed.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/BladeLocatorLed.java
new file mode 100644
index 0000000..cd74bd6
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/BladeLocatorLed.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.BladeLocatorLedDto;
+
+/**
+ * Adds high level functionality to {@link BladeLocatorLedDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href=
+ *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-Retrievethelocatorledoftheblade"
+ *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+ *      Retrievethelocatorledoftheblade</a>
+ */
+@EnterpriseEdition
+public class BladeLocatorLed extends DomainWrapper<BladeLocatorLedDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected BladeLocatorLed(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final BladeLocatorLedDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate Methods
+
+    public String getAdminStatus()
+    {
+        return target.getAdminStatus();
+    }
+
+    public String getBladeDn()
+    {
+        return target.getBladeDn();
+    }
+
+    public String getColor()
+    {
+        return target.getColor();
+    }
+
+    public String getDn()
+    {
+        return target.getDn();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "BladeLocatorLed [Dn=" + getDn() + ", BladeDn=" + getBladeDn() + ", Color="
+            + getColor() + ", AdminStatus=" + getAdminStatus() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Datacenter.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Datacenter.java
new file mode 100644
index 0000000..80ef2e8
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Datacenter.java
@@ -0,0 +1,1174 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.config.AbiquoEdition;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.Limits;
+import org.jclouds.abiquo.domain.infrastructure.options.DatacenterOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.IpmiOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.MachineOptions;
+import org.jclouds.abiquo.domain.network.Network;
+import org.jclouds.abiquo.domain.network.options.NetworkOptions;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.MachineIpmiState;
+import com.abiquo.model.enumerator.MachineState;
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.abiquo.model.enumerator.VlanTagAvailabilityType;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.abiquo.server.core.cloud.HypervisorTypeDto;
+import com.abiquo.server.core.cloud.HypervisorTypesDto;
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.MachineIpmiStateDto;
+import com.abiquo.server.core.infrastructure.MachineStateDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.abiquo.server.core.infrastructure.RacksDto;
+import com.abiquo.server.core.infrastructure.RemoteServicesDto;
+import com.abiquo.server.core.infrastructure.UcsRackDto;
+import com.abiquo.server.core.infrastructure.UcsRacksDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.abiquo.server.core.infrastructure.network.VlanTagAvailabilityDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDevicesDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDevicesMetadataDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link DatacenterDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/DatacenterResource">
+ *      http://community.abiquo.com/display/ABI20/DatacenterResource</a>
+ */
+public class Datacenter extends DomainWrapper<DatacenterDto>
+{
+    /**
+     * IP address of the datacenter (used to create all remote services with the same ip).
+     */
+    private String ip;
+
+    /**
+     * Indicates the Abiquo edition to create the available remote services.
+     * 
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/Introduction+-+The+Abiquo+Platform">
+     *      http://community.abiquo.com/display/ABI20/Introduction+-+The+Abiquo+Platform</a>
+     */
+    private AbiquoEdition edition;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Datacenter(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final DatacenterDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Delete the datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-DeleteanexistingDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      DeleteanexistingDatacenter</a>
+     */
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteDatacenter(target);
+        target = null;
+    }
+
+    /**
+     * Create a datacenter in Abiquo. This method will perform several calls to the API if remote
+     * services have been defined in the builder. Different remote services will be created
+     * depending on the {@link AbiquoEdition}.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-CreateanewDatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      CreateanewDatacenter</a>
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-CreateaRemoteService"
+     *      > http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-
+     *      CreateaRemoteService</a>
+     */
+    public void save()
+    {
+        // Datacenter must be persisted first, so links get populated in the target object
+        target = context.getApi().getInfrastructureApi().createDatacenter(target);
+
+        // If remote services data is set, create remote services.
+        if (ip != null && edition != null)
+        {
+            createRemoteServices();
+        }
+    }
+
+    /**
+     * Update datacenter information in the server with the data from this datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Updateanexistingdatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Updateanexistingdatacenter </a>
+     */
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateDatacenter(target);
+    }
+
+    /**
+     * The cloud administrator will find it useful to know if a VLAN Tag is already assigned before
+     * creating a new Public or External Network. This method provides this functionality: Check if
+     * a tag is available inside the Datacenter. Please refer link for more information.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-Checkthetagavailability"
+     *      > http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-
+     *      Checkthetagavailability</a>
+     * @return Availability state of the tag.
+     */
+    public VlanTagAvailabilityType checkTagAvailability(final int tag)
+    {
+        VlanTagAvailabilityDto availability =
+            context.getApi().getInfrastructureApi().checkTagAvailability(target, tag);
+
+        return availability.getAvailable();
+    }
+
+    // Children access
+
+    /**
+     * Retrieve the list of unmanaged racks in this datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofRacks"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofRacks</a>
+     * @return List of unmanaged racks in this datacenter.
+     */
+    public List<Rack> listRacks()
+    {
+        RacksDto racks = context.getApi().getInfrastructureApi().listRacks(target);
+        return wrap(context, Rack.class, racks.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of unmanaged racks in this datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofRacks"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofRacks</a>
+     * @return Filtered list of unmanaged racks in this datacenter.
+     */
+    public List<Rack> listRacks(final Predicate<Rack> filter)
+    {
+        return Lists.newLinkedList(filter(listRacks(), filter));
+    }
+
+    /**
+     * Retrieve the first unmanaged rack matching the filter within the list of racks in this
+     * datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofRacks"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofRacks</a>
+     * @return First unmanaged rack matching the filter or <code>null</code> if the is none.
+     */
+    public Rack findRack(final Predicate<Rack> filter)
+    {
+        return Iterables.getFirst(filter(listRacks(), filter), null);
+    }
+
+    /**
+     * Retrieve a single unmanaged rack.
+     * 
+     * @param id Unique ID of the rack in this datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveaRack" >
+     *      http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveaRack</a>
+     * @return Unmanaged rack with the given id or <code>null</code> if it does not exist.
+     */
+    public Rack getRack(final Integer id)
+    {
+        RackDto rack = context.getApi().getInfrastructureApi().getRack(target, id);
+        return wrap(context, Rack.class, rack);
+    }
+
+    /**
+     * Retrieve the list of managed racks in this datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofUCSracks"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofUCSracks</a>
+     * @return List of managed racks in this datacenter.
+     */
+    @EnterpriseEdition
+    public List<ManagedRack> listManagedRacks()
+    {
+        UcsRacksDto racks = context.getApi().getInfrastructureApi().listManagedRacks(target);
+        return wrap(context, ManagedRack.class, racks.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of managed racks in this datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofUCSracks"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofUCSracks</a>
+     * @return Filtered list of managed racks in this datacenter.
+     */
+    @EnterpriseEdition
+    public List<ManagedRack> listManagedRacks(final Predicate<ManagedRack> filter)
+    {
+        return Lists.newLinkedList(filter(listManagedRacks(), filter));
+    }
+
+    /**
+     * Retrieve the first managed rack matching the filter within the list of racks in this
+     * datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofUCSracks"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofUCSracks</a>
+     * @return First managed rack matching the filter or <code>null</code> if there is none.
+     */
+    @EnterpriseEdition
+    public ManagedRack findManagedRack(final Predicate<ManagedRack> filter)
+    {
+        return Iterables.getFirst(filter(listManagedRacks(), filter), null);
+    }
+
+    /**
+     * Retrieve a single managed rack.
+     * 
+     * @param id Unique ID of the rack in this datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveaUCSRack" >
+     *      http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveaUCSRack</a>
+     * @return Unmanaged rack with the given id or <code>null</code> if it does not exist.
+     */
+    @EnterpriseEdition
+    public ManagedRack getManagedRack(final Integer id)
+    {
+        UcsRackDto rack = context.getApi().getInfrastructureApi().getManagedRack(target, id);
+        return wrap(context, ManagedRack.class, rack);
+    }
+
+    /**
+     * Retrieve the list of supported storage devices.
+     * <p>
+     * This method will get the list of the storage devices that are supported in the datacenter.
+     * 
+     * @return List of supported storage devices. This list has only the default information for the
+     *         storage devices, such as the management and iscsi ports, or the default credentials
+     *         to access the device.
+     */
+    @EnterpriseEdition
+    public List<StorageDeviceMetadata> listSupportedStorageDevices()
+    {
+        StorageDevicesMetadataDto devices =
+            context.getApi().getInfrastructureApi().listSupportedStorageDevices(target);
+        return wrap(context, StorageDeviceMetadata.class, devices.getCollection());
+    }
+
+    /**
+     * Retrieve the list of supported storage devices matching the filter.
+     * <p>
+     * This method will get the list of the storage devices that are supported in the datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @return List of supported storage devices. This list has only the default information for the
+     *         storage devices, such as the management and iscsi ports, or the default credentials
+     *         to access the device.
+     */
+    @EnterpriseEdition
+    public List<StorageDeviceMetadata> listSupportedStorageDevices(
+        final Predicate<StorageDeviceMetadata> filter)
+    {
+        return Lists.newLinkedList(filter(listSupportedStorageDevices(), filter));
+    }
+
+    /**
+     * Retrieve a single supported storage devices matching the filter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @return First supported storage device matching the filter or <code>null</code> if there is
+     *         none.
+     */
+    @EnterpriseEdition
+    public StorageDeviceMetadata findSupportedStorageDevice(
+        final Predicate<StorageDeviceMetadata> filter)
+    {
+        return Iterables.getFirst(filter(listSupportedStorageDevices(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of storage devices in this datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Retrievethelistofstoragedevices"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Retrievethelistofstoragedevices</a>
+     * @return List of storage devices in this datacenter.
+     */
+    @EnterpriseEdition
+    public List<StorageDevice> listStorageDevices()
+    {
+        StorageDevicesDto devices =
+            context.getApi().getInfrastructureApi().listStorageDevices(target);
+        return wrap(context, StorageDevice.class, devices.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of storage devices in this datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Retrievethelistofstoragedevices"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Retrievethelistofstoragedevices</a>
+     * @return Filtered list of storage devices in this datacenter.
+     */
+    @EnterpriseEdition
+    public List<StorageDevice> listStorageDevices(final Predicate<StorageDevice> filter)
+    {
+        return Lists.newLinkedList(filter(listStorageDevices(), filter));
+    }
+
+    /**
+     * Retrieve the first storage device matching the filter within the list of devices in this
+     * datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Retrievethelistofstoragedevices"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Retrievethelistofstoragedevices</a>
+     * @return First storage device matching the filter or <code>null</code> if there is none.
+     */
+    @EnterpriseEdition
+    public StorageDevice findStorageDevice(final Predicate<StorageDevice> filter)
+    {
+        return Iterables.getFirst(filter(listStorageDevices(), filter), null);
+    }
+
+    /**
+     * Retrieve a single storage device.
+     * 
+     * @param id Unique ID of the storage device in this datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Retrieveastoragedevice"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Retrieveastoragedevice</a>
+     * @return Storage device with the given id or <code>null</code> if it does not exist.
+     */
+    @EnterpriseEdition
+    public StorageDevice getStorageDevice(final Integer id)
+    {
+        StorageDeviceDto device =
+            context.getApi().getInfrastructureApi().getStorageDevice(target, id);
+        return wrap(context, StorageDevice.class, device);
+    }
+
+    /**
+     * Retrieve the list of remote services of this datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-RetrievealistofRemoteServices"
+     *      > http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-
+     *      RetrievealistofRemoteServices</a>
+     * @return List of remote services in this datacenter.
+     */
+    public List<RemoteService> listRemoteServices()
+    {
+        RemoteServicesDto remoteServices =
+            context.getApi().getInfrastructureApi().listRemoteServices(target);
+        return wrap(context, RemoteService.class, remoteServices.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of remote services of this datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-RetrievealistofRemoteServices"
+     *      > http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-
+     *      RetrievealistofRemoteServices</a>
+     * @return Filtered list of remote services in this datacenter.
+     */
+    public List<RemoteService> listRemoteServices(final Predicate<RemoteService> filter)
+    {
+        return Lists.newLinkedList(filter(listRemoteServices(), filter));
+    }
+
+    /**
+     * Retrieve the first remote service matching the filter within the list of remote services in
+     * this datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-RetrievealistofRemoteServices"
+     *      > http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-
+     *      RetrievealistofRemoteServices</a>
+     * @return First remote service matching the filter or <code>null</code> if there is none.
+     */
+    public RemoteService findRemoteService(final Predicate<RemoteService> filter)
+    {
+        return Iterables.getFirst(filter(listRemoteServices(), filter), null);
+    }
+
+    private void createRemoteServices()
+    {
+        if (this.edition == AbiquoEdition.ENTERPRISE)
+        {
+            createRemoteService(RemoteServiceType.BPM_SERVICE);
+            createRemoteService(RemoteServiceType.DHCP_SERVICE);
+            createRemoteService(RemoteServiceType.STORAGE_SYSTEM_MONITOR);
+        }
+
+        createRemoteService(RemoteServiceType.APPLIANCE_MANAGER);
+        createRemoteService(RemoteServiceType.VIRTUAL_SYSTEM_MONITOR);
+        createRemoteService(RemoteServiceType.NODE_COLLECTOR);
+        createRemoteService(RemoteServiceType.VIRTUAL_FACTORY);
+    }
+
+    private void createRemoteService(final RemoteServiceType type)
+    {
+        RemoteService.builder(context, this).type(type).ip(this.ip).build().save();
+    }
+
+    /**
+     * Retrieve the list of datacenter limits by all enterprises. The Datacenter Limits resource
+     * allows you to assign datacenters and allocated resources in them to be used by an enterprise.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrievelimitsbydatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrievelimitsbydatacenter</a>
+     * @return List of datacenter limits by all enterprises.
+     */
+    public List<Limits> listLimits()
+    {
+        DatacentersLimitsDto dto =
+            context.getApi().getInfrastructureApi().listLimits(this.unwrap());
+        return DomainWrapper.wrap(context, Limits.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of datacenter limits by enterprises. The Datacenter Limits resource
+     * allows you to assign datacenters and allocated resources in them to be used by an enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrievelimitsbydatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrievelimitsbydatacenter</a>
+     * @return Filtered list of datacenter limits by all enterprises.
+     */
+    public List<Limits> listLimits(final Predicate<Limits> filter)
+    {
+        return Lists.newLinkedList(filter(listLimits(), filter));
+    }
+
+    /**
+     * Retrieve the first datacenter limits matching the filter within the list of datacenter limits
+     * by enterprise. The Datacenter Limits resource allows you to assign datacenters and allocated
+     * resources in them to be used by an enterprise.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrievelimitsbydatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrievelimitsbydatacenter</a>
+     * @return First datacenter limits matching the filter or <code>null</code> if there is none.
+     */
+    public Limits findLimits(final Predicate<Limits> filter)
+    {
+        return Iterables.getFirst(filter(listLimits(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of tiers in ths datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TierResource#TierResource-Retrievethelistoftiers"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/TierResource#TierResource-Retrievethelistoftiers
+     *      </a>
+     * @return List of tiers in this datacenter.
+     */
+    @EnterpriseEdition
+    public List<Tier> listTiers()
+    {
+        TiersDto dto = context.getApi().getInfrastructureApi().listTiers(this.unwrap());
+        return DomainWrapper.wrap(context, Tier.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of tiers in this datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TierResource#TierResource-Retrievethelistoftiers"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/TierResource#TierResource-Retrievethelistoftiers
+     *      </a>
+     * @return Filtered list of tiers in this datacenter.
+     */
+    @EnterpriseEdition
+    public List<Tier> listTiers(final Predicate<Tier> filter)
+    {
+        return Lists.newLinkedList(filter(listTiers(), filter));
+    }
+
+    /**
+     * Retrieve the first tier matching the filter within the list of tiers in this datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Retrievethelistofstoragedevices"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Retrievethelistofstoragedevices</a>
+     * @return First tier matching the filter or <code>null</code> if there is none.
+     */
+    @EnterpriseEdition
+    public Tier findTier(final Predicate<Tier> filter)
+    {
+        return Iterables.getFirst(filter(listTiers(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of public, external and unmanaged networks in this datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-Getthelistofpublicnetworks"
+     *      > http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-
+     *      Getthelistofpublicnetworks</a>
+     * @return List of public, external and unmanaged networks in this datacenter.
+     */
+    public List<Network< ? >> listNetworks()
+    {
+        VLANNetworksDto networks = context.getApi().getInfrastructureApi().listNetworks(target);
+        return Network.wrapNetworks(context, networks.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of public, external and unmanaged networks in this datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-Getthelistofpublicnetworks"
+     *      > http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-
+     *      Getthelistofpublicnetworks</a>
+     */
+    public List<Network< ? >> listNetworks(final Predicate<Network< ? >> filter)
+    {
+        return Lists.newLinkedList(filter(listNetworks(), filter));
+    }
+
+    /**
+     * Retrieve the first network matching the filter within the list of networks.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-Getthelistofpublicnetworks"
+     *      > http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-
+     *      Getthelistofpublicnetworks</a>
+     * @return Filtered list of public, external and unmanaged networks in this datacenter.
+     */
+    public Network< ? > findNetwork(final Predicate<Network< ? >> filter)
+    {
+        return Iterables.getFirst(filter(listNetworks(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of networks of this datacenter matching the given type.
+     * 
+     * @param type Network type filter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-Getthelistofpublicnetworks"
+     *      > http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-
+     *      Getthelistofpublicnetworks</a>
+     * @return List of networks of this datacenter matching the given type.
+     */
+    public List<Network< ? >> listNetworks(final NetworkType type)
+    {
+        NetworkOptions options = NetworkOptions.builder().type(type).build();
+        VLANNetworksDto networks =
+            context.getApi().getInfrastructureApi().listNetworks(target, options);
+        return Network.wrapNetworks(context, networks.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of networks of this datacenter matching the given type.
+     * 
+     * @param type Network type filter.
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-Getthelistofpublicnetworks"
+     *      > http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-
+     *      Getthelistofpublicnetworks</a>
+     * @return Filtered list of networks of this datacenter matching the given type.
+     */
+    public List<Network< ? >> listNetworks(final NetworkType type,
+        final Predicate<Network< ? >> filter)
+    {
+        return Lists.newLinkedList(filter(listNetworks(type), filter));
+    }
+
+    /**
+     * Retrieve the first network of the given type matching the filter.
+     * 
+     * @param type Network type filter.
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-Getthelistofpublicnetworks"
+     *      > http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-
+     *      Getthelistofpublicnetworks</a>
+     * @return First network of the given type matching the filter or <code>null</code> if there is
+     *         none.
+     */
+    public Network< ? > findNetwork(final NetworkType type, final Predicate<Network< ? >> filter)
+    {
+        return Iterables.getFirst(filter(listNetworks(type), filter), null);
+    }
+
+    /**
+     * Retrieve a single public, external or unmanaged network from this datacenter.
+     * {@link org.jclouds.abiquo.domain.network.Network#toExternalNetwork},
+     * {@link org.jclouds.abiquo.domain.network.Network#toPublicNetwork} and
+     * {@link org.jclouds.abiquo.domain.network.Network#toUnmanagedNetwork} can be used to convert
+     * the Network into the appropiate domain object.
+     * 
+     * @param id Unique ID of the network in this datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/PublicNetworkResource#PublicNetworkResource-Getthelistofpublicnetworks"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#PublicNetworkResource#
+     *      PublicNetworkResource-Getthelistofpublicnetworks</a>
+     * @return Network with the given id or <code>null</code> if it does not exist.
+     */
+    public Network< ? > getNetwork(final Integer id)
+    {
+        VLANNetworkDto network = context.getApi().getInfrastructureApi().getNetwork(target, id);
+        return Network.wrapNetwork(context, network);
+    }
+
+    // Actions
+
+    /**
+     * Retrieve the hypervisor type from remote machine.
+     * 
+     * @param ip IP address of the physical machine.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrievethehypervisortypefromremotemachine"
+     *      http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrievethehypervisortypefromremotemachine</a>
+     * @return Hypervisor type of the remote machine.
+     * @throws Exception If the hypervisor type information cannot be retrieved.
+     */
+    public HypervisorType getHypervisorType(final String ip)
+    {
+        DatacenterOptions options = DatacenterOptions.builder().ip(ip).build();
+
+        String type =
+            context.getApi().getInfrastructureApi().getHypervisorTypeFromMachine(target, options);
+
+        return HypervisorType.valueOf(type);
+    }
+
+    /**
+     * Retrieve the list of available hypervisor types in the datacenter.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveavailablehypervisortypes"
+     *      http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveavailablehypervisortypes</a>
+     * @return List of available hypervisor types in the datacenter.
+     */
+    @EnterpriseEdition
+    public List<HypervisorType> listAvailableHypervisors()
+    {
+        HypervisorTypesDto types =
+            context.getApi().getInfrastructureApi().getHypervisorTypes(target);
+
+        return getHypervisorTypes(types);
+    }
+
+    /**
+     * Retrieve a filtered list of available hypervisor types in the datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveavailablehypervisortypes"
+     *      http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveavailablehypervisortypes</a>
+     * @return Filtered list of available hypervisor types in the datacenter.
+     */
+    @EnterpriseEdition
+    public List<HypervisorType> listAvailableHypervisors(final Predicate<HypervisorType> filter)
+    {
+        return Lists.newLinkedList(filter(listAvailableHypervisors(), filter));
+    }
+
+    /**
+     * Retrieve the first hypervisor type matching the filter within the list of types.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveavailablehypervisortypes"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveavailablehypervisortypes</a>
+     * @return First hypervisor type matching the filter or <code>null</code> if there is none.
+     */
+    @EnterpriseEdition
+    public HypervisorType findHypervisor(final Predicate<HypervisorType> filter)
+    {
+        return Iterables.getFirst(filter(listAvailableHypervisors(), filter), null);
+    }
+
+    private List<HypervisorType> getHypervisorTypes(final HypervisorTypesDto dtos)
+    {
+        List<HypervisorType> types = Lists.newArrayList();
+
+        for (HypervisorTypeDto dto : dtos.getCollection())
+        {
+            types.add(HypervisorType.fromId(dto.getId()));
+        }
+
+        return types;
+    }
+
+    /**
+     * Searches a remote machine and retrieves an Machine object with its information.
+     * 
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return A physical machine if found or <code>null</code>.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveremotemachineinformation</a>
+     */
+    public Machine discoverSingleMachine(final String ip, final HypervisorType hypervisorType,
+        final String user, final String password)
+    {
+        return discoverSingleMachine(ip, hypervisorType, user, password, hypervisorType.defaultPort);
+    }
+
+    /**
+     * Searches a remote machine and retrieves an Machine object with its information.
+     * 
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @param port Port to connect.
+     * @return A physical machine if found or <code>null</code>.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveremotemachineinformation</a>
+     */
+    public Machine discoverSingleMachine(final String ip, final HypervisorType hypervisorType,
+        final String user, final String password, final int port)
+    {
+        MachineDto dto =
+            context
+                .getApi()
+                .getInfrastructureApi()
+                .discoverSingleMachine(target, ip, hypervisorType, user, password,
+                    MachineOptions.builder().port(port).build());
+
+        // Credentials are not returned by the API
+        dto.setUser(user);
+        dto.setPassword(password);
+
+        return wrap(context, Machine.class, dto);
+    }
+
+    /**
+     * Searches multiple remote machines and retrieves an Machine list with its information.
+     * 
+     * @param ipFrom IP address of the remote first hypervisor to check.
+     * @param ipTo IP address of the remote last hypervisor to check.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return The physical machine list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrievealistofremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrievealistofremotemachineinformation</a>
+     */
+    public List<Machine> discoverMultipleMachines(final String ipFrom, final String ipTo,
+        final HypervisorType hypervisorType, final String user, final String password)
+    {
+        return discoverMultipleMachines(ipFrom, ipTo, hypervisorType, user, password,
+            hypervisorType.defaultPort);
+    }
+
+    /**
+     * Searches multiple remote machines and retrieves an Machine list with its information.
+     * 
+     * @param ipFrom IP address of the remote first hypervisor to check.
+     * @param ipTo IP address of the remote last hypervisor to check.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @param port Port to connect.
+     * @return The physical machine list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrievealistofremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrievealistofremotemachineinformation</a>
+     */
+    public List<Machine> discoverMultipleMachines(final String ipFrom, final String ipTo,
+        final HypervisorType hypervisorType, final String user, final String password,
+        final int port)
+    {
+        MachinesDto dto =
+            context
+                .getApi()
+                .getInfrastructureApi()
+                .discoverMultipleMachines(target, ipFrom, ipTo, hypervisorType, user, password,
+                    MachineOptions.builder().port(port).build());
+
+        // Credentials are not returned by the API
+        for (MachineDto machine : dto.getCollection())
+        {
+            machine.setUser(user);
+            machine.setPassword(password);
+        }
+
+        return wrap(context, Machine.class, dto.getCollection());
+    }
+
+    /**
+     * Check the state of a remote machine. This feature is used to check the state from a remote
+     * machine giving its location, user, password and hypervisor type. This machine does not need
+     * to be managed by Abiquo.
+     * 
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return The physical machine state if the machine is found or <code>null</code>.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Checkthestatefromremotemachine"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Checkthestatefromremotemachine</a>
+     */
+    public MachineState checkMachineState(final String ip, final HypervisorType hypervisorType,
+        final String user, final String password)
+    {
+        return checkMachineState(ip, hypervisorType, user, password,
+            MachineOptions.builder().port(hypervisorType.defaultPort).build());
+    }
+
+    /**
+     * Check the state of a remote machine. This feature is used to check the state from a remote
+     * machine giving its location, user, password and hypervisor type. This machine does not need
+     * to be managed by Abiquo.
+     * 
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @param options.
+     * @return The physical machine state if the machine is found or <code>null</code>.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Checkthestatefromremotemachine"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Checkthestatefromremotemachine</a>
+     */
+    public MachineState checkMachineState(final String ip, final HypervisorType hypervisorType,
+        final String user, final String password, final MachineOptions options)
+    {
+        MachineStateDto dto =
+            context.getApi().getInfrastructureApi()
+                .checkMachineState(target, ip, hypervisorType, user, password, options);
+
+        return dto.getState();
+    }
+
+    /**
+     * Check the ipmi configuration state of a remote machine. This feature is used to check the
+     * ipmi configuration state from a remote machine giving its location, user and password. This
+     * machine does not need to be managed by Abiquo.
+     * 
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return The physical machine state if the machine is found or <code>null</code>.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Checktheipmistatefromremotemachine"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Checktheipmistatefromremotemachine</a>
+     */
+    public MachineIpmiState checkMachineIpmiState(final String ip, final String user,
+        final String password)
+    {
+        MachineIpmiStateDto dto =
+            context.getApi().getInfrastructureApi()
+                .checkMachineIpmiState(target, ip, user, password);
+        return dto.getState();
+    }
+
+    /**
+     * Check the ipmi configuration state of a remote machine. This feature is used to check the
+     * ipmi configuration state from a remote machine giving its location, user and password. This
+     * machine does not need to be managed by Abiquo.
+     * 
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return The physical machine state if the machine is found or <code>null</code>.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Checktheipmistatefromremotemachine"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Checktheipmistatefromremotemachine</a>
+     */
+    public MachineIpmiState checkMachineIpmiState(final String ip, final String user,
+        final String password, final IpmiOptions options)
+    {
+        MachineIpmiStateDto dto =
+            context.getApi().getInfrastructureApi()
+                .checkMachineIpmiState(target, ip, user, password, options);
+        return dto.getState();
+    }
+
+    /**
+     * Retrieve the list of virtual machine templates in the repository of this datacenter.
+     * 
+     * @param enterprise Owner of the templates.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineTemplateResource#VirtualMachineTemplateResource-Retrieveallvirtualmachinetemplates"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineTemplateResource#
+     *      VirtualMachineTemplateResource-Retrieveallvirtualmachinetemplates</a>
+     * @return List of virtual machine templates in the repository of this datacenter.
+     */
+    public List<VirtualMachineTemplate> listTemplatesInRepository(final Enterprise enterprise)
+    {
+        VirtualMachineTemplatesDto dto =
+            context.getApi().getVirtualMachineTemplateApi()
+                .listVirtualMachineTemplates(enterprise.getId(), target.getId());
+        return wrap(context, VirtualMachineTemplate.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of virtual machine templates in the repository of this datacenter.
+     * 
+     * @param enterprise Owner of the templates.
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineTemplateResource#VirtualMachineTemplateResource-Retrieveallvirtualmachinetemplates"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineTemplateResource#
+     *      VirtualMachineTemplateResource-Retrieveallvirtualmachinetemplates</a>
+     * @return Filtered list of virtual machine templates in the repository of this datacenter.
+     */
+    public List<VirtualMachineTemplate> listTemplatesInRepository(final Enterprise enterprise,
+        final Predicate<VirtualMachineTemplate> filter)
+    {
+        return Lists.newLinkedList(filter(listTemplatesInRepository(enterprise), filter));
+    }
+
+    /**
+     * Retrieve the first virtual machine template within the list of templates of this datacenter
+     * from the given enterprise.
+     * 
+     * @param enterprise Owner of the templates.
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineTemplateResource#VirtualMachineTemplateResource-Retrieveallvirtualmachinetemplates"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineTemplateResource#
+     *      VirtualMachineTemplateResource-Retrieveallvirtualmachinetemplates</a>
+     * @return First virtual machine template matching the filter or <code>null</code> if there is
+     *         none.
+     */
+    public VirtualMachineTemplate findTemplateInRepository(final Enterprise enterprise,
+        final Predicate<VirtualMachineTemplate> filter)
+    {
+        return Iterables.getFirst(filter(listTemplatesInRepository(enterprise), filter), null);
+    }
+
+    /**
+     * Retrieve a single virtual machine template in of this datacenter from the given enterprise.
+     * 
+     * @param enterprise Owner of the templates.
+     * @param id Unique ID of the template in the datacenter repository for the given enterprise.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/VirtualMachineTemplateResource#VirtualMachineTemplateResource-Retrieveallvirtualmachinetemplates"
+     *      > http://community.abiquo.com/display/ABI20/VirtualMachineTemplateResource#
+     *      VirtualMachineTemplateResource-Retrieveallvirtualmachinetemplates</a>
+     * @return Virtual machine template with the given id in the given enterpriess or
+     *         <code>null</code> if it does not exist.
+     */
+    public VirtualMachineTemplate getTemplateInRepository(final Enterprise enterprise,
+        final Integer id)
+    {
+        VirtualMachineTemplateDto template =
+            context.getApi().getVirtualMachineTemplateApi()
+                .getVirtualMachineTemplate(enterprise.getId(), target.getId(), id);
+        return wrap(context, VirtualMachineTemplate.class, template);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        return new Builder(context);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name;
+
+        private String location;
+
+        private String ip;
+
+        private AbiquoEdition edition;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+        {
+            super();
+            this.context = context;
+        }
+
+        public Builder remoteServices(final String ip, final AbiquoEdition edition)
+        {
+            this.ip = ip;
+            this.edition = edition;
+            return this;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder location(final String location)
+        {
+            this.location = location;
+            return this;
+        }
+
+        public Datacenter build()
+        {
+            DatacenterDto dto = new DatacenterDto();
+            dto.setName(name);
+            dto.setLocation(location);
+            Datacenter datacenter = new Datacenter(context, dto);
+            datacenter.edition = edition;
+            datacenter.ip = ip;
+            return datacenter;
+        }
+
+        public static Builder fromDatacenter(final Datacenter in)
+        {
+            return Datacenter.builder(in.context).name(in.getName()).location(in.getLocation());
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getLocation()
+    {
+        return target.getLocation();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public void setLocation(final String location)
+    {
+        target.setLocation(location);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public String getUUID()
+    {
+        return target.getUuid();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Datacenter [id=" + getId() + ", location=" + getLocation() + ", name=" + getName()
+            + ", uuid=" + getUUID() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Datastore.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Datastore.java
new file mode 100644
index 0000000..65709d4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Datastore.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.DatastoreDto;
+
+/**
+ * Adds high level functionality to {@link DatastoreDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class Datastore extends DomainWrapper<DatastoreDto>
+{
+    /**
+     * Constructor to be used only by the builder. This resource cannot be created.
+     */
+    private Datastore(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final DatastoreDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate methods
+
+    public String getDatastoreUUID()
+    {
+        return target.getDatastoreUUID();
+    }
+
+    public String getDirectory()
+    {
+        return target.getDirectory();
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getRootPath()
+    {
+        return target.getRootPath();
+    }
+
+    public long getSize()
+    {
+        return target.getSize();
+    }
+
+    public long getUsedSize()
+    {
+        return target.getUsedSize();
+    }
+
+    public boolean isEnabled()
+    {
+        return target.isEnabled();
+    }
+
+    public void setEnabled(final boolean enabled)
+    {
+        target.setEnabled(enabled);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Datastore [id=" + getId() + ", uuid=" + getDatastoreUUID() + ", directory="
+            + getDirectory() + ", name=" + getName() + ", rootPath=" + getRootPath() + ", size="
+            + getSize() + ", usedSize=" + getUsedSize() + ", enabled=" + isEnabled() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Fsm.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Fsm.java
new file mode 100644
index 0000000..bdf5945
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Fsm.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.FsmDto;
+
+/**
+ * Adds high level functionality to {@link FsmDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Rack+Resource">
+ *      http://community.abiquo.com/display/ABI20/Rack+Resource</a>
+ */
+@EnterpriseEdition
+public class Fsm extends DomainWrapper<FsmDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Fsm(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final FsmDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate Methods
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    public String getDn()
+    {
+        return target.getDn();
+    }
+
+    public String getError()
+    {
+        return target.getError();
+    }
+
+    public String getProgress()
+    {
+        return target.getProgress();
+    }
+
+    public String getStatus()
+    {
+        return target.getStatus();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Fsm [Dn=" + getDn() + ", Description=" + getDescription() + ", Error=" + getError()
+            + ", Progress=" + getProgress() + ", Status=" + getStatus() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/LogicServer.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/LogicServer.java
new file mode 100644
index 0000000..8969b85
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/LogicServer.java
@@ -0,0 +1,102 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+import com.abiquo.server.core.infrastructure.LogicServerPolicyDto;
+
+/**
+ * Adds high level functionality to {@link LogicServerDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Rack+Resource">
+ *      http://community.abiquo.com/display/ABI20/Rack+Resource</a>
+ */
+@EnterpriseEdition
+public class LogicServer extends DomainWrapper<LogicServerDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected LogicServer(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final LogicServerDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate Methods
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public void setType(final String value)
+    {
+        target.setType(value);
+    }
+
+    public String getAssociated()
+    {
+        return target.getAssociated();
+    }
+
+    public String getType()
+    {
+        return target.getType();
+    }
+
+    public String getAssociatedTo()
+    {
+        return target.getAssociatedTo();
+    }
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    public void setDescription(final String value)
+    {
+        target.setDescription(value);
+    }
+
+    public List<LogicServerPolicyDto> getCollection()
+    {
+        return target.getCollection();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "LogicServer [name=" + getName() + ", associated=" + getAssociated() + ", type="
+            + getType() + ", associatedTo=" + getAssociatedTo() + ", description="
+            + getDescription() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Machine.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Machine.java
new file mode 100644
index 0000000..d361685
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Machine.java
@@ -0,0 +1,549 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.find;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.options.MachineOptions;
+import org.jclouds.abiquo.predicates.infrastructure.DatastorePredicates;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.MachineState;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.DatastoresDto;
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.MachineStateDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to {@link MachineDto}. This resource allows you to manage physical
+ * machines in the cloud infrastructure.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/MachineResource">
+ *      http://community.abiquo.com/display/ABI20/MachineResource</a>
+ */
+public class Machine extends AbstractPhysicalMachine
+{
+    /** The rack where the machine belongs. */
+    protected Rack rack;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Machine(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final MachineDto target)
+    {
+        super(context, target);
+    }
+
+    /**
+     * Create a new physical machine in Abiquo. The best way to create a machine if first calling
+     * {@link Datacenter#discoverSingleMachine} or {@link Datacenter#discoverMultipleMachines}. This
+     * will return a new {@link Machine}. The following steps are: enabling a datastore, selecting a
+     * virtual switch and choosing a rack. Refer link for more information.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveremotemachineinformation</a>
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-Createamachine"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      Createamachine</a>
+     */
+    public void save()
+    {
+        target = context.getApi().getInfrastructureApi().createMachine(rack.unwrap(), target);
+    }
+
+    @Override
+    public MachineState check()
+    {
+        MachineStateDto dto =
+            context.getApi().getInfrastructureApi().checkMachineState(target, true);
+        MachineState state = dto.getState();
+        target.setState(state);
+        return state;
+    }
+
+    // Parent access
+    /**
+     * Retrieve the unmanaged rack where the machine is.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveaRack" >
+     *      http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveaRack</a>
+     */
+    public Rack getRack()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.RACK),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.RACK);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<RackDto> parser =
+            new ParseXMLWithJAXB<RackDto>(utils.getXml(), TypeLiteral.get(RackDto.class));
+
+        return wrap(context, Rack.class, parser.apply(response));
+    }
+
+    // Children access
+
+    @Override
+    public List<Datastore> getDatastores()
+    {
+        return wrap(context, Datastore.class, target.getDatastores().getCollection());
+    }
+
+    @Override
+    public Datastore findDatastore(final String name)
+    {
+        return find(getDatastores(), DatastorePredicates.name(name), null);
+    }
+
+    /**
+     * Gets the list of virtual machines in the physical machine.
+     * 
+     * @return The list of virtual machines in the physical machine.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Machine+Resource#MachineResource-Retrievethelistofvirtualmachinesbymachine'shypervisor"
+     *      > http://community.abiquo.com/display/ABI20/Machine+Resource#MachineResource-
+     *      Retrievethelistofvirtualmachinesbymachine'shypervisor</a>
+     */
+    public List<VirtualMachine> listVirtualMachines()
+    {
+        MachineOptions options = MachineOptions.builder().sync(false).build();
+        VirtualMachinesWithNodeExtendedDto vms =
+            context.getApi().getInfrastructureApi().listVirtualMachinesByMachine(target, options);
+        return wrap(context, VirtualMachine.class, vms.getCollection());
+    }
+
+    /**
+     * Gets the list of virtual machines in the physical machine matching the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The list of virtual machines in the physical machine matching the given filter.
+     */
+    public List<VirtualMachine> listVirtualMachines(final Predicate<VirtualMachine> filter)
+    {
+        return Lists.newLinkedList(filter(listVirtualMachines(), filter));
+    }
+
+    /**
+     * Gets a single virtual machine in the physical machine matching the given filter.
+     * 
+     * @param filter The filter to apply.
+     * @return The virtual machine or <code>null</code> if none matched the given filter.
+     */
+    public VirtualMachine findVirtualMachine(final Predicate<VirtualMachine> filter)
+    {
+        return Iterables.getFirst(filter(listVirtualMachines(), filter), null);
+    }
+
+    /**
+     * Gets the list of virtual machines in the physical machine sinchronizing virtual machines from
+     * remote hypervisor with abiquo's database.
+     * 
+     * @return The list of virtual machines in the physical machine.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Machine+Resource#MachineResource-Retrievethelistofvirtualmachinesbymachine'shypervisor"
+     *      > http://community.abiquo.com/display/ABI20/Machine+Resource#MachineResource-
+     *      Retrievethelistofvirtualmachinesbymachine'shypervisor</a>
+     */
+    public List<VirtualMachine> listRemoteVirtualMachines()
+    {
+        MachineOptions options = MachineOptions.builder().sync(true).build();
+        VirtualMachinesWithNodeExtendedDto vms =
+            context.getApi().getInfrastructureApi().listVirtualMachinesByMachine(target, options);
+        return wrap(context, VirtualMachine.class, vms.getCollection());
+    }
+
+    /**
+     * Gets the list of virtual machines in the physical machine matching the given filter
+     * sinchronizing virtual machines from remote hypervisor with abiquo's database.
+     * 
+     * @param filter The filter to apply.
+     * @return The list of remote virtual machines in the physical machine matching the given
+     *         filter.
+     */
+    public List<VirtualMachine> listRemoteVirtualMachines(final Predicate<VirtualMachine> filter)
+    {
+        return Lists.newLinkedList(filter(listVirtualMachines(), filter));
+    }
+
+    /**
+     * Gets a single virtual machine in the physical machine matching the given filter sinchronizing
+     * virtual machines from remote hypervisor with abiquo's database.
+     * 
+     * @param filter The filter to apply.
+     * @return The virtual machine or <code>null</code> if none matched the given filter.
+     */
+    public VirtualMachine findRemoteVirtualMachine(final Predicate<VirtualMachine> filter)
+    {
+        return Iterables.getFirst(filter(listVirtualMachines(), filter), null);
+    }
+
+    /**
+     * Reserve the machine for the given enterprise.
+     * <p>
+     * When a {@link Machine} is reserved for an {@link Enterprise}, only the users of that
+     * enterprise will be able to deploy {@link VirtualMachine}s in it.
+     * 
+     * @param enterprise The enterprise reserving the machine.
+     */
+    public void reserveFor(final Enterprise enterprise)
+    {
+        target =
+            context.getApi().getInfrastructureApi().reserveMachine(enterprise.unwrap(), target);
+    }
+
+    /**
+     * Cancels the machine reservation for the given enterprise.
+     * 
+     * @param enterprise The enterprise to cancel reservation for.
+     */
+    public void cancelReservationFor(final Enterprise enterprise)
+    {
+        context.getApi().getInfrastructureApi().cancelReservation(enterprise.unwrap(), target);
+        target.getLinks().remove(target.searchLink(ParentLinkName.ENTERPRISE));
+    }
+
+    /**
+     * Check if the machine is reserved.
+     * 
+     * @return Boolean indicating if the machine is reserved for an enterprise.
+     */
+    public boolean isReserved()
+    {
+        return target.searchLink(ParentLinkName.ENTERPRISE) != null;
+    }
+
+    /**
+     * Get the enterprise that has reserved the machine or <code>null</code> if the machine is not
+     * reserved.
+     * 
+     * @return The enterprise that has reserved the machine or <code>null</code> if the machine is
+     *         not reserved.
+     */
+    public Enterprise getOwnerEnterprise()
+    {
+        if (!isReserved())
+        {
+            return null;
+        }
+
+        EnterpriseDto enterprise =
+            context.getApi().getEnterpriseApi()
+                .getEnterprise(target.getIdFromLink(ParentLinkName.ENTERPRISE));
+
+        return wrap(context, Enterprise.class, enterprise);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Rack rack)
+    {
+        return new Builder(context, rack);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private String name, description;
+
+        private Integer virtualRamInMb;
+
+        private Integer virtualRamUsedInMb = DEFAULT_VRAM_USED;
+
+        private Integer virtualCpuCores;
+
+        private Integer virtualCpusUsed = DEFAULT_VCPU_USED;
+
+        private String virtualSwitch;
+
+        private Integer port;
+
+        private String ip;
+
+        private MachineState state = MachineState.STOPPED;
+
+        private String ipService;
+
+        private HypervisorType type;
+
+        private String user;
+
+        private String password;
+
+        private Iterable<Datastore> datastores;
+
+        private String ipmiIp;
+
+        private Integer ipmiPort;
+
+        private String ipmiUser;
+
+        private String ipmiPassword;
+
+        private Rack rack;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final Rack rack)
+        {
+            super();
+            checkNotNull(rack, ValidationErrors.NULL_RESOURCE + Rack.class);
+            this.rack = rack;
+            this.context = context;
+        }
+
+        public Builder state(final MachineState state)
+        {
+            this.state = state;
+            return this;
+        }
+
+        public Builder ipmiPassword(final String ipmiPassword)
+        {
+            this.ipmiPassword = ipmiPassword;
+            return this;
+        }
+
+        public Builder ipmiUser(final String ipmiUser)
+        {
+            this.ipmiUser = ipmiUser;
+            return this;
+        }
+
+        public Builder ipmiPort(final int ipmiPort)
+        {
+            this.ipmiPort = ipmiPort;
+            return this;
+        }
+
+        public Builder ipmiIp(final String ipmiIp)
+        {
+            this.ipmiIp = ipmiIp;
+            return this;
+        }
+
+        public Builder user(final String user)
+        {
+            this.user = user;
+            return this;
+        }
+
+        public Builder ip(final String ip)
+        {
+            this.ip = ip;
+            if (ipService == null)
+            {
+                ipService = ip;
+            }
+            return this;
+        }
+
+        public Builder ipService(final String ipService)
+        {
+            this.ipService = ipService;
+            return this;
+        }
+
+        public Builder password(final String password)
+        {
+            this.password = password;
+            return this;
+        }
+
+        public Builder virtualSwitch(final String virtualSwitch)
+        {
+            this.virtualSwitch = virtualSwitch;
+            return this;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder description(final String description)
+        {
+            this.description = description;
+            return this;
+        }
+
+        public Builder port(final int port)
+        {
+            this.port = port;
+            return this;
+        }
+
+        public Builder datastores(final Iterable<Datastore> datastores)
+        {
+            this.datastores = datastores;
+            return this;
+        }
+
+        public Builder virtualRamInMb(final int virtualRamInMb)
+        {
+            this.virtualRamInMb = virtualRamInMb;
+            return this;
+        }
+
+        public Builder virtualRamUsedInMb(final int virtualRamUsedInMb)
+        {
+            this.virtualRamUsedInMb = virtualRamUsedInMb;
+            return this;
+        }
+
+        public Builder virtualCpuCores(final int virtualCpuCores)
+        {
+            this.virtualCpuCores = virtualCpuCores;
+            return this;
+        }
+
+        public Builder virtualCpusUsed(final int virtualCpusUsed)
+        {
+            this.virtualCpusUsed = virtualCpusUsed;
+            return this;
+        }
+
+        public Builder hypervisorType(final HypervisorType hypervisorType)
+        {
+            this.type = hypervisorType;
+
+            // Sets default hypervisor port
+            if (this.port == null)
+            {
+                this.port = hypervisorType.defaultPort;
+            }
+
+            return this;
+        }
+
+        public Builder rack(final Rack rack)
+        {
+            checkNotNull(rack, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.rack = rack;
+            return this;
+        }
+
+        public Machine build()
+        {
+            MachineDto dto = new MachineDto();
+            dto.setName(name);
+            dto.setDescription(description);
+            dto.setVirtualRamInMb(virtualRamInMb);
+            dto.setVirtualRamUsedInMb(virtualRamUsedInMb);
+            dto.setVirtualCpuCores(virtualCpuCores);
+            dto.setVirtualCpusUsed(virtualCpusUsed);
+            dto.setVirtualSwitch(virtualSwitch);
+            if (port != null)
+            {
+                dto.setPort(port);
+            }
+            dto.setIp(ip);
+            dto.setIpService(ipService);
+            dto.setType(type);
+            dto.setUser(user);
+            dto.setPassword(password);
+            dto.setIpmiIP(ipmiIp);
+            dto.setIpmiPassword(ipmiPassword);
+            if (ipmiPort != null)
+            {
+                dto.setIpmiPort(ipmiPort);
+            }
+            dto.setIpmiUser(ipmiUser);
+            dto.setState(state);
+
+            DatastoresDto datastoresDto = new DatastoresDto();
+            datastoresDto.getCollection().addAll(unwrap(datastores));
+            dto.setDatastores(datastoresDto);
+
+            Machine machine = new Machine(context, dto);
+            machine.rack = rack;
+
+            return machine;
+        }
+
+        public static Builder fromMachine(final Machine in)
+        {
+            Builder builder =
+                Machine.builder(in.context, in.rack).name(in.getName())
+                    .description(in.getDescription()).virtualCpuCores(in.getVirtualCpuCores())
+                    .virtualCpusUsed(in.getVirtualCpusUsed())
+                    .virtualRamInMb(in.getVirtualRamInMb())
+                    .virtualRamUsedInMb(in.getVirtualRamUsedInMb())
+                    .virtualSwitch(in.getVirtualSwitch()).port(in.getPort()).ip(in.getIp())
+                    .ipService(in.getIpService()).hypervisorType(in.getType()).user(in.getUser())
+                    .password(in.getPassword()).ipmiIp(in.getIpmiIp())
+                    .ipmiPassword(in.getIpmiPassword()).ipmiUser(in.getIpmiUser())
+                    .state(in.getState()).datastores(in.getDatastores());
+
+            // Parameters that can be null
+            if (in.getIpmiPort() != null)
+            {
+                builder.ipmiPort(in.getIpmiPort());
+            }
+
+            return builder;
+        }
+    }
+
+    // Delegate methods
+
+    public void setRack(final Rack rack)
+    {
+        this.rack = rack;
+    }
+
+    public VirtualMachine getVirtualMachine(final Integer virtualMachineId)
+    {
+        VirtualMachineWithNodeExtendedDto vm =
+            context.getApi().getInfrastructureApi().getVirtualMachine(target, virtualMachineId);
+        return wrap(context, VirtualMachine.class, vm);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/ManagedRack.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/ManagedRack.java
new file mode 100644
index 0000000..94dba1d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/ManagedRack.java
@@ -0,0 +1,786 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.FsmsDto;
+import com.abiquo.server.core.infrastructure.LogicServersDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.OrganizationsDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.abiquo.server.core.infrastructure.UcsRackDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link RackDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/RackResource">
+ *      http://community.abiquo.com/display/ABI20/RackResource</a>
+ */
+@EnterpriseEdition
+public class ManagedRack extends DomainWrapper<UcsRackDto>
+{
+    /** The default minimum VLAN id. */
+    private static final int DEFAULT_VLAN_ID_MIN = 2;
+
+    /** The default maximum VLAN id. */
+    private static final int DEFAULT_VLAN_ID_MAX = 4094;
+
+    /** The default maximum VLAN per virtual datacenter. */
+    private static final int DEFAULT_VLAN_PER_VDC = 1;
+
+    /** The default nrsq factor. */
+    private static final int DEFAULT_NRSQ = 10;
+
+    /** The datacenter where the rack belongs. */
+    private Datacenter datacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected ManagedRack(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final UcsRackDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Delete the managed rack.
+     * 
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/RackResource#RackResource-DeleteaRack" >
+     *      http://community.abiquo.com/display/ABI20/Rack+Resource#RackResource#RackResource-
+     *      DeleteaRack</a>
+     */
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteRack(target);
+        target = null;
+    }
+
+    /**
+     * Create a new managed rack in Abiquo. This method wil discover the blades configured in the
+     * UCS. If the data provided for the connection is invalid a UcsRack will be created in Abiquo
+     * but with no Physical Machines attached to it.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-CreateanewUCSRack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-CreateanewUCSRack<
+     *      /a>
+     */
+    public void save()
+    {
+        target =
+            context.getApi().getInfrastructureApi()
+                .createManagedRack(datacenter.unwrap(), target);
+    }
+
+    /**
+     * Update rack information in the server with the data from this rack. The IP data member cannot
+     * be updated. If changed will be ignored and the old IP will remain.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource#RackResource-UpdateanexistingUCSrack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource#RackResource-
+     *      UpdateanexistingUCSrack</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateManagedRack(target);
+    }
+
+    // Parent access
+    /**
+     * Retrieve the datacenter where this rack is.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveadatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveadatacenter</a>
+     */
+    public Datacenter getDatacenter()
+    {
+        Integer datacenterId = target.getIdFromLink(ParentLinkName.DATACENTER);
+        return wrap(context, Datacenter.class, context.getApi().getInfrastructureApi()
+            .getDatacenter(datacenterId));
+    }
+
+    // Children access
+
+    /**
+     * Retrieve the list of blades in this rack.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrievealistofMachines"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      RetrievealistofMachines</a>
+     */
+    public List<Blade> listMachines()
+    {
+        MachinesDto machines = context.getApi().getInfrastructureApi().listMachines(target);
+        return wrap(context, Blade.class, machines.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of blades in this rack.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrievealistofMachines"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      RetrievealistofMachines</a>
+     */
+    public List<Blade> listMachines(final Predicate<Blade> filter)
+    {
+        return Lists.newLinkedList(filter(listMachines(), filter));
+    }
+
+    /**
+     * Retrieve the first blade matching the filter within the list of machines in this rack.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrievealistofMachines"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      RetrievealistofMachines</a>
+     */
+    public Blade findMachine(final Predicate<Blade> filter)
+    {
+        return Iterables.getFirst(filter(listMachines(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of service profiles in this UCS rack.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofallservicesprofilesinaUCSrack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofallservicesprofilesinaUCSrack</a>
+     */
+    public List<LogicServer> listServiceProfiles()
+    {
+        LogicServersDto profiles =
+            context.getApi().getInfrastructureApi().listServiceProfiles(target);
+        return wrap(context, LogicServer.class, profiles.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of service profiles in this UCS rack.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofallservicesprofilesinaUCSrack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofallservicesprofilesinaUCSrack</a>
+     */
+    public List<LogicServer> listServiceProfiles(final Predicate<LogicServer> filter)
+    {
+        return Lists.newLinkedList(filter(listServiceProfiles(), filter));
+    }
+
+    /**
+     * Retrieve the first service profile matching the filter within the list of profiles in this
+     * rack.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrievealistofallservicesprofilesinaUCSrack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrievealistofallservicesprofilesinaUCSrack</a>
+     */
+    public LogicServer findServiceProfile(final Predicate<LogicServer> filter)
+    {
+        return Iterables.getFirst(filter(listServiceProfiles(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of service profile templates in this UCS rack.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource-RetrievealistofallServicesProfilesTemplatesinaUCSRack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource-
+     *      RetrievealistofallServicesProfilesTemplatesinaUCSRack</a>
+     */
+    public List<LogicServer> listServiceProfileTemplates()
+    {
+        LogicServersDto templates =
+            context.getApi().getInfrastructureApi().listServiceProfileTemplates(target);
+        return wrap(context, LogicServer.class, templates.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of service profile templates in this UCS rack.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource-RetrievealistofallServicesProfilesTemplatesinaUCSRack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource-
+     *      RetrievealistofallServicesProfilesTemplatesinaUCSRack</a>
+     */
+    public List<LogicServer> listServiceProfileTemplates(final Predicate<LogicServer> filter)
+    {
+        return Lists.newLinkedList(filter(listServiceProfileTemplates(), filter));
+    }
+
+    /**
+     * Retrieve the first service profile template matching the filter within the list of templates
+     * in this rack.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource-RetrievealistofallServicesProfilesTemplatesinaUCSRack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource-
+     *      RetrievealistofallServicesProfilesTemplatesinaUCSRack</a>
+     */
+    public LogicServer findServiceProfileTemplate(final Predicate<LogicServer> filter)
+    {
+        return Iterables.getFirst(filter(listServiceProfileTemplates(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of organization in this UCS rack. The credentials in the UcsRack
+     * configuration might not have enough rights in the UCS to retrieve all organizations. Then
+     * only the allowed ones are returned. This data is not persisted in Abiquo.
+     * 
+     * @see API: <a href= "http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrieveallorganizationsfromaUCS"> http://community.abiquo.com/display/ABI20/</a>
+     */
+    public List<Organization> listOrganizations()
+    {
+        OrganizationsDto organizations =
+            context.getApi().getInfrastructureApi().listOrganizations(target);
+        return wrap(context, Organization.class, organizations.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of organization in this UCS rack. The credentials in the UcsRack
+     * configuration might not have enough rights in the UCS to retrieve all organizations. Then
+     * only the allowed ones are returned. This data is not persisted in Abiquo.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href= "http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrieveallorganizationsfromaUCS" >
+     *      http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrieveallorganizationsfromaUCS</a>
+     */
+    public List<Organization> listOrganizations(final Predicate<Organization> filter)
+    {
+        return Lists.newLinkedList(filter(listOrganizations(), filter));
+    }
+
+    /**
+     * Retrieve the first organization matching the filter within the list of organization in this
+     * rack. The credentials in the UcsRack configuration might not have enough rights in the UCS to
+     * retrieve all organizations. Then only the allowed ones are returned. This data is not
+     * persisted in Abiquo.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href= "http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrieveallorganizationsfromaUCS">
+     *      http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrieveallorganizationsfromaUCS</a>
+     */
+    public Organization findOrganization(final Predicate<Organization> filter)
+    {
+        return Iterables.getFirst(filter(listOrganizations(), filter), null);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-RetrieveFSMofanentityinUCS"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      RetrieveFSMofanentityinUCS</a>
+     */
+    public List<Fsm> listFsm(final String entityName)
+    {
+        FsmsDto fsms = context.getApi().getInfrastructureApi().listFsms(target, entityName);
+        return wrap(context, Fsm.class, fsms.getCollection());
+    }
+
+    // Actions
+
+    /**
+     * Clone a Service Profile this rack. This data is not persisted in Abiquo.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-ClonelogicserverinUCS"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      ClonelogicserverinUCS</a>
+     */
+    public void cloneLogicServer(final LogicServer logicServer, final Organization organization,
+        final String newName)
+    {
+        context.getApi().getInfrastructureApi()
+            .cloneLogicServer(this.unwrap(), logicServer.unwrap(), organization.unwrap(), newName);
+    }
+
+    /**
+     * Associate a Service Profile and a Blade in UCS. If the Service Profile is already associated
+     * then the request cannot be completed. This data is not persisted in Abiquo.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-AssociatelogicserverwithabladeinUCS"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      AssociatelogicserverwithabladeinUCS</a>
+     */
+    public void associateLogicServer(final String bladeName, final LogicServer logicServer,
+        final Organization organization)
+    {
+        context
+            .getApi()
+            .getInfrastructureApi()
+            .associateLogicServer(this.unwrap(), logicServer.unwrap(), organization.unwrap(),
+                bladeName);
+    }
+
+    /**
+     * Clone and associate a Service Profile and a Blade in UCS. If the Blade is already associated
+     * then Abiquo will dissociate it first. If the request cannot be completed successfully the
+     * Blade might be left with no Service Profile associated. This data is not persisted in Abiquo.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-CloneandassociateLogicServerwithabladeinUCS"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      CloneandassociateLogicServerwithabladeinUCS</a>
+     */
+    public void cloneAndAssociateLogicServer(final String bladeName, final LogicServer logicServer,
+        final Organization organization, final String logicServerName)
+    {
+        context
+            .getApi()
+            .getInfrastructureApi()
+            .cloneAndAssociateLogicServer(this.unwrap(), logicServer.unwrap(),
+                organization.unwrap(), bladeName, logicServerName);
+    }
+
+    /**
+     * Instantiate and associate a Service Profile Template and a Blade in UCS. If the Service
+     * Profile is already associated the request cannot be successful. If the Blade is already
+     * associated then Abiquo will dissociate it first. If the request cannot be completed
+     * successfully the Blade might be left with no Service Profile associated. This data is not
+     * persisted in Abiquo.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-AssociateabladewithaLogicServerTemplate"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      AssociateabladewithaLogicServerTemplate</a>
+     */
+    public void associateLogicServerTemplate(final String bladeName, final LogicServer logicServer,
+        final Organization organization, final String logicServerName)
+    {
+        context
+            .getApi()
+            .getInfrastructureApi()
+            .associateTemplate(this.unwrap(), logicServer.unwrap(), organization.unwrap(),
+                bladeName, logicServerName);
+    }
+
+    /**
+     * Dissociates a Service Profile and a Blade in UCS. This data is not persisted in Abiquo.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-DisassociatelogicserverfromabladeinUCS"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      DisassociatelogicserverfromabladeinUCS</a>
+     */
+    public void disassociateLogicServer(final LogicServer logicServer)
+    {
+        context.getApi().getInfrastructureApi()
+            .dissociateLogicServer(this.unwrap(), logicServer.unwrap());
+    }
+
+    /**
+     * Deletes a Service Profile in UCS. This data is not persisted in Abiquo.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-DeletelogicserverwithabladeinUCS"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-
+     *      DeletelogicserverwithabladeinUCS</a>
+     */
+    public void deleteLogicServer(final LogicServer logicServer)
+    {
+        context.getApi().getInfrastructureApi()
+            .deleteLogicServer(this.unwrap(), logicServer.unwrap());
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Datacenter datacenter)
+    {
+        return new Builder(context, datacenter);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private Integer id;
+
+        private String name;
+
+        private String shortDescription;
+
+        private boolean haEnabled = false;
+
+        private Integer nrsq = DEFAULT_NRSQ;
+
+        private Integer vlanIdMax = DEFAULT_VLAN_ID_MAX;
+
+        private Integer vlanIdMin = DEFAULT_VLAN_ID_MIN;
+
+        private Integer vlanPerVdcReserved = DEFAULT_VLAN_PER_VDC;
+
+        private String vlansIdAvoided;
+
+        private Integer port;
+
+        private String ip;
+
+        private String password;
+
+        private String user;
+
+        private String defaultTemplate;
+
+        private Integer maxMachinesOn;
+
+        private Datacenter datacenter;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Datacenter datacenter)
+        {
+            super();
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            this.context = context;
+        }
+
+        public Builder port(final Integer port)
+        {
+            this.port = port;
+            return this;
+        }
+
+        public Builder ipAddress(final String ip)
+        {
+            this.ip = ip;
+            return this;
+        }
+
+        public Builder password(final String password)
+        {
+            this.password = password;
+            return this;
+        }
+
+        public Builder user(final String user)
+        {
+            this.user = user;
+            return this;
+        }
+
+        public Builder defaultTemplate(final String defaultTemplate)
+        {
+            this.defaultTemplate = defaultTemplate;
+            return this;
+        }
+
+        public Builder maxMachinesOn(final Integer maxMachinesOn)
+        {
+            this.maxMachinesOn = maxMachinesOn;
+            return this;
+        }
+
+        public Builder id(final Integer id)
+        {
+            this.id = id;
+            return this;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder shortDescription(final String shortDescription)
+        {
+            this.shortDescription = shortDescription;
+            return this;
+        }
+
+        public Builder haEnabled(final boolean haEnabled)
+        {
+            this.haEnabled = haEnabled;
+            return this;
+        }
+
+        public Builder nrsq(final int nrsq)
+        {
+            this.nrsq = nrsq;
+            return this;
+        }
+
+        public Builder vlanIdMax(final int vlanIdMax)
+        {
+            this.vlanIdMax = vlanIdMax;
+            return this;
+        }
+
+        public Builder vlanIdMin(final int vlanIdMin)
+        {
+            this.vlanIdMin = vlanIdMin;
+            return this;
+        }
+
+        public Builder vlanPerVdcReserved(final int vlanPerVdcExpected)
+        {
+            this.vlanPerVdcReserved = vlanPerVdcExpected;
+            return this;
+        }
+
+        public Builder VlansIdAvoided(final String vlansIdAvoided)
+        {
+            this.vlansIdAvoided = vlansIdAvoided;
+            return this;
+        }
+
+        public Builder datacenter(final Datacenter datacenter)
+        {
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            return this;
+        }
+
+        public ManagedRack build()
+        {
+            UcsRackDto dto = new UcsRackDto();
+            dto.setId(id);
+            dto.setName(name);
+            dto.setShortDescription(shortDescription);
+            dto.setHaEnabled(haEnabled);
+            dto.setNrsq(nrsq);
+            dto.setVlanIdMax(vlanIdMax);
+            dto.setVlanIdMin(vlanIdMin);
+            dto.setVlanPerVdcReserved(vlanPerVdcReserved);
+            dto.setVlansIdAvoided(vlansIdAvoided);
+            dto.setPort(port);
+            dto.setIp(ip);
+            dto.setPassword(password);
+            dto.setUser(user);
+            dto.setDefaultTemplate(defaultTemplate);
+            dto.setMaxMachinesOn(maxMachinesOn);
+
+            ManagedRack rack = new ManagedRack(context, dto);
+            rack.datacenter = datacenter;
+            return rack;
+        }
+
+        public static Builder fromRack(final ManagedRack in)
+        {
+            return ManagedRack.builder(in.context, in.datacenter).id(in.getId()).name(in.getName())
+                .shortDescription(in.getShortDescription()).haEnabled(in.isHaEnabled())
+                .nrsq(in.getNrsq()).vlanIdMax(in.getVlanIdMax()).vlanIdMin(in.getVlanIdMin())
+                .vlanPerVdcReserved(in.getVlanPerVdcReserved())
+                .VlansIdAvoided(in.getVlansIdAvoided()).port(in.getPort()).ipAddress(in.getIp())
+                .password(in.getPassword()).user(in.getUser())
+                .defaultTemplate(in.getDefaultTemplate()).maxMachinesOn(in.getMaxMachinesOn());
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getShortDescription()
+    {
+        return target.getShortDescription();
+    }
+
+    public void setShortDescription(final String description)
+    {
+        target.setShortDescription(description);
+    }
+
+    public void setHaEnabled(final boolean haEnabled)
+    {
+        target.setHaEnabled(haEnabled);
+    }
+
+    public boolean isHaEnabled()
+    {
+        return target.isHaEnabled();
+    }
+
+    public Integer getNrsq()
+    {
+        return target.getNrsq();
+    }
+
+    public Integer getVlanIdMax()
+    {
+        return target.getVlanIdMax();
+    }
+
+    public Integer getVlanIdMin()
+    {
+        return target.getVlanIdMin();
+    }
+
+    public Integer getVlanPerVdcReserved()
+    {
+        return target.getVlanPerVdcReserved();
+    }
+
+    public String getVlansIdAvoided()
+    {
+        return target.getVlansIdAvoided();
+    }
+
+    public void setNrsq(final Integer nrsq)
+    {
+        target.setNrsq(nrsq);
+    }
+
+    public void setVlanIdMax(final Integer vlanIdMax)
+    {
+        target.setVlanIdMax(vlanIdMax);
+    }
+
+    public void setVlanIdMin(final Integer vlanIdMin)
+    {
+        target.setVlanIdMin(vlanIdMin);
+    }
+
+    public void setVlanPerVdcReserved(final Integer vlanPerVdcReserved)
+    {
+        target.setVlanPerVdcReserved(vlanPerVdcReserved);
+    }
+
+    public void setVlansIdAvoided(final String vlansIdAvoided)
+    {
+        target.setVlansIdAvoided(vlansIdAvoided);
+    }
+
+    public String getIp()
+    {
+        return target.getIp();
+    }
+
+    public String getLongDescription()
+    {
+        return target.getLongDescription();
+    }
+
+    public Integer getMaxMachinesOn()
+    {
+        return target.getMaxMachinesOn();
+    }
+
+    public String getPassword()
+    {
+        return target.getPassword();
+    }
+
+    public Integer getPort()
+    {
+        return target.getPort();
+    }
+
+    public String getUser()
+    {
+        return target.getUser();
+    }
+
+    public void setDefaultTemplate(final String defaultTemplate)
+    {
+        target.setDefaultTemplate(defaultTemplate);
+    }
+
+    public String getDefaultTemplate()
+    {
+        return target.getDefaultTemplate();
+    }
+
+    public void setIp(final String ip)
+    {
+        target.setIp(ip);
+    }
+
+    public void setMaxMachinesOn(final Integer maxMachinesOn)
+    {
+        target.setMaxMachinesOn(maxMachinesOn);
+    }
+
+    public void setPassword(final String password)
+    {
+        target.setPassword(password);
+    }
+
+    public void setPort(final Integer port)
+    {
+        target.setPort(port);
+    }
+
+    public void setUser(final String user)
+    {
+        target.setUser(user);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "ManagedRack [id=" + getId() + ", name=" + getName() + ", shortDescription="
+            + getShortDescription() + ", haEnabled=" + isHaEnabled() + ", nrsq=" + getNrsq()
+            + ", vlanIdMax=" + getVlanIdMax() + ", vlanIdMin=" + getVlanIdMin()
+            + ", vlanPerVdcReserved=" + getVlanPerVdcReserved() + ", vlansIdAvoided="
+            + getVlansIdAvoided() + ", ip=" + getIp() + ", longDescription=" + getLongDescription()
+            + ", maxMachinesOn=" + getMaxMachinesOn() + ", password=**PROTECTED**, port="
+            + getPort() + ", user=" + getUser() + ", defaultTemplate=" + getDefaultTemplate() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Organization.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Organization.java
new file mode 100644
index 0000000..6fafe38
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Organization.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.OrganizationDto;
+
+/**
+ * Adds high level functionality to {@link OrganizationDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/RackResource">
+ *      http://community.abiquo.com/display/ABI20/RackResource</a>
+ */
+@EnterpriseEdition
+public class Organization extends DomainWrapper<OrganizationDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Organization(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final OrganizationDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate Methods
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    public String getDn()
+    {
+        return target.getDn();
+    }
+
+    public String getLevel()
+    {
+        return target.getLevel();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getStatus()
+    {
+        return target.getStatus();
+    }
+
+    public void setDescription(final String value)
+    {
+        target.setDescription(value);
+    }
+
+    public void setDn(final String dn)
+    {
+        target.setDn(dn);
+    }
+
+    public void setLevel(final String value)
+    {
+        target.setLevel(value);
+    }
+
+    public void setName(final String value)
+    {
+        target.setName(value);
+    }
+
+    public void setStatus(final String value)
+    {
+        target.setStatus(value);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Organization [name=" + getName() + ", description=" + getDescription() + ", dn="
+            + getDn() + ", level=" + getLevel() + ", status=" + getStatus() + "]";
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Rack.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Rack.java
new file mode 100644
index 0000000..6777fac
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Rack.java
@@ -0,0 +1,421 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link RackDto}. Represents unmanaged racks in the Abiquo
+ * platform.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/RackResource">
+ *      http://community.abiquo.com/display/ABI20/RackResource</a>
+ */
+public class Rack extends DomainWrapper<RackDto>
+{
+    /** The default minimum VLAN id. */
+    private static final int DEFAULT_VLAN_ID_MIN = 2;
+
+    /** The default maximum VLAN id. */
+    private static final int DEFAULT_VLAN_ID_MAX = 4094;
+
+    /** The default maximum VLAN per virtual datacenter. */
+    private static final int DEFAULT_VLAN_PER_VDC = 1;
+
+    /** The default nrsq factor. */
+    private static final int DEFAULT_NRSQ = 10;
+
+    /** The datacenter where the rack belongs. */
+    private Datacenter datacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Rack(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final RackDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Delete the unmanaged rack.
+     * 
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/RackResource#RackResource-DeleteaRack" >
+     *      http://community.abiquo.com/display/ABI20/Rack+Resource#RackResource#RackResource-
+     *      DeleteaRack</a>
+     */
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteRack(target);
+        target = null;
+    }
+
+    /**
+     * Create a new unmanaged rack in Abiquo.
+     * 
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/RackResource#RackResource-CreateanewRack"
+     *      > http://community.abiquo.com/display/ABI20/RackResource#RackResource-CreateanewRack</a>
+     */
+    public void save()
+    {
+        target = context.getApi().getInfrastructureApi().createRack(datacenter.unwrap(), target);
+    }
+
+    /**
+     * Update rack information in the server with the data from this rack.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RackResource#RackResource-UpdateanexistingRack"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/RackResource#RackResource-UpdateanexistingRack
+     *      </a>
+     */
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateRack(target);
+    }
+
+    // Parent access
+    /**
+     * Retrieve the datacenter where this rack is.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveadatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveadatacenter</a>
+     */
+    public Datacenter getDatacenter()
+    {
+        Integer datacenterId = target.getIdFromLink(ParentLinkName.DATACENTER);
+        return wrap(context, Datacenter.class, context.getApi().getInfrastructureApi()
+            .getDatacenter(datacenterId));
+    }
+
+    // Children access
+
+    /**
+     * Retrieve the list of physical machines in this rack.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrievealistofMachines"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      RetrievealistofMachines</a>
+     */
+    public List<Machine> listMachines()
+    {
+        MachinesDto machines = context.getApi().getInfrastructureApi().listMachines(target);
+        return wrap(context, Machine.class, machines.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of physical machines in this rack.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrievealistofMachines"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      RetrievealistofMachines</a>
+     */
+    public List<Machine> listMachines(final Predicate<Machine> filter)
+    {
+        return Lists.newLinkedList(filter(listMachines(), filter));
+    }
+
+    /**
+     * Retrieve the first physical machine matching the filter within the list of machines in this
+     * rack.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrievealistofMachines"
+     *      > http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-
+     *      RetrievealistofMachines</a>
+     */
+    public Machine findMachine(final Predicate<Machine> filter)
+    {
+        return Iterables.getFirst(filter(listMachines(), filter), null);
+    }
+
+    /**
+     * Retrieve a single physical machine.
+     * 
+     * @param id Unique ID of the physical machine in this rack.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrieveaMachine"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/MachineResource#MachineResource-RetrieveaMachine
+     *      </a>
+     * @return Unmanaged rack with the given id or <code>null</code> if it does not exist.
+     */
+    public Machine getMachine(final Integer id)
+    {
+        MachineDto machine = context.getApi().getInfrastructureApi().getMachine(target, id);
+        return wrap(context, Machine.class, machine);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Datacenter datacenter)
+    {
+        return new Builder(context, datacenter);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private Integer id;
+
+        private String name;
+
+        private String shortDescription;
+
+        private boolean haEnabled = false;
+
+        private Integer nrsq = DEFAULT_NRSQ;
+
+        private Integer vlanIdMax = DEFAULT_VLAN_ID_MAX;
+
+        private Integer vlanIdMin = DEFAULT_VLAN_ID_MIN;
+
+        private Integer vlanPerVdcReserved = DEFAULT_VLAN_PER_VDC;
+
+        private String vlansIdAvoided;
+
+        private Datacenter datacenter;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Datacenter datacenter)
+        {
+            super();
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            this.context = context;
+        }
+
+        public Builder id(final Integer id)
+        {
+            this.id = id;
+            return this;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder shortDescription(final String shortDescription)
+        {
+            this.shortDescription = shortDescription;
+            return this;
+        }
+
+        public Builder haEnabled(final boolean haEnabled)
+        {
+            this.haEnabled = haEnabled;
+            return this;
+        }
+
+        public Builder nrsq(final int nrsq)
+        {
+            this.nrsq = nrsq;
+            return this;
+        }
+
+        public Builder vlanIdMax(final int vlanIdMax)
+        {
+            this.vlanIdMax = vlanIdMax;
+            return this;
+        }
+
+        public Builder vlanIdMin(final int vlanIdMin)
+        {
+            this.vlanIdMin = vlanIdMin;
+            return this;
+        }
+
+        public Builder vlanPerVdcReserved(final int vlanPerVdcExpected)
+        {
+            this.vlanPerVdcReserved = vlanPerVdcExpected;
+            return this;
+        }
+
+        public Builder VlansIdAvoided(final String vlansIdAvoided)
+        {
+            this.vlansIdAvoided = vlansIdAvoided;
+            return this;
+        }
+
+        public Builder datacenter(final Datacenter datacenter)
+        {
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            return this;
+        }
+
+        public Rack build()
+        {
+            RackDto dto = new RackDto();
+            dto.setId(id);
+            dto.setName(name);
+            dto.setShortDescription(shortDescription);
+            dto.setHaEnabled(haEnabled);
+            dto.setNrsq(nrsq);
+            dto.setVlanIdMax(vlanIdMax);
+            dto.setVlanIdMin(vlanIdMin);
+            dto.setVlanPerVdcReserved(vlanPerVdcReserved);
+            dto.setVlansIdAvoided(vlansIdAvoided);
+            Rack rack = new Rack(context, dto);
+            rack.datacenter = datacenter;
+            return rack;
+        }
+
+        public static Builder fromRack(final Rack in)
+        {
+            return Rack.builder(in.context, in.datacenter).id(in.getId()).name(in.getName())
+                .shortDescription(in.getShortDescription()).haEnabled(in.isHaEnabled())
+                .nrsq(in.getNrsq()).vlanIdMax(in.getVlanIdMax()).vlanIdMin(in.getVlanIdMin())
+                .vlanPerVdcReserved(in.getVlanPerVdcReserved())
+                .VlansIdAvoided(in.getVlansIdAvoided());
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getShortDescription()
+    {
+        return target.getShortDescription();
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setShortDescription(final String description)
+    {
+        target.setShortDescription(description);
+    }
+
+    public void setHaEnabled(final boolean haEnabled)
+    {
+        target.setHaEnabled(haEnabled);
+    }
+
+    public boolean isHaEnabled()
+    {
+        return target.isHaEnabled();
+    }
+
+    public Integer getNrsq()
+    {
+        return target.getNrsq();
+    }
+
+    public Integer getVlanIdMax()
+    {
+        return target.getVlanIdMax();
+    }
+
+    public Integer getVlanIdMin()
+    {
+        return target.getVlanIdMin();
+    }
+
+    public Integer getVlanPerVdcReserved()
+    {
+        return target.getVlanPerVdcReserved();
+    }
+
+    public String getVlansIdAvoided()
+    {
+        return target.getVlansIdAvoided();
+    }
+
+    public void setNrsq(final Integer nrsq)
+    {
+        target.setNrsq(nrsq);
+    }
+
+    public void setVlanIdMax(final Integer vlanIdMax)
+    {
+        target.setVlanIdMax(vlanIdMax);
+    }
+
+    public void setVlanIdMin(final Integer vlanIdMin)
+    {
+        target.setVlanIdMin(vlanIdMin);
+    }
+
+    public void setVlanPerVdcReserved(final Integer vlanPerVdcReserved)
+    {
+        target.setVlanPerVdcReserved(vlanPerVdcReserved);
+    }
+
+    public void setVlansIdAvoided(final String vlansIdAvoided)
+    {
+        target.setVlansIdAvoided(vlansIdAvoided);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Rack [id=" + getId() + ", name=" + getName() + ", description="
+            + getShortDescription() + ", haEnabled=" + isHaEnabled() + ", nrsq=" + getNrsq()
+            + ", vlanIdMax=" + getVlanIdMax() + ", vlanIdMin=" + getVlanIdMin()
+            + ", vlanPerVdcReserved=" + getVlanPerVdcReserved() + ", vlansIdAvoided="
+            + getVlansIdAvoided() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/RemoteService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/RemoteService.java
new file mode 100644
index 0000000..568a742
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/RemoteService.java
@@ -0,0 +1,277 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.RemoteServiceDto;
+
+/**
+ * Adds high level functionality to {@link RemoteServiceDto}. The Remote Service resource offers the
+ * functionality of managing the remote services of a datacenter in a logical way.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/RemoteServiceResource">
+ *      http://community.abiquo.com/display/ABI20/RemoteServiceResource</a>
+ */
+public class RemoteService extends DomainWrapper<RemoteServiceDto>
+{
+    /** The default status. */
+    private static final int DEFAULT_STATUS = 0;
+
+    /** The datacenter using the remote service. */
+    private Datacenter datacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected RemoteService(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final RemoteServiceDto target)
+    {
+        super(context, target);
+    }
+
+    /**
+     * Delete the remote service.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-DeleteaRemoteService"
+     *      > http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-
+     *      DeleteaRemoteService</a>
+     */
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteRemoteService(target);
+        target = null;
+    }
+
+    /**
+     * Create the remote service.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-CreateaRemoteService"
+     *      > http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-
+     *      CreateaRemoteService</a>
+     */
+    public void save()
+    {
+        target =
+            context.getApi().getInfrastructureApi()
+                .createRemoteService(datacenter.unwrap(), target);
+    }
+
+    /**
+     * Update remote service information in the server with the data from this remote service.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-UpdateanexistingRemoteService"
+     *      > http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-
+     *      UpdateanexistingRemoteService</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateRemoteService(target);
+    }
+
+    /**
+     * Check remote service availability.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-CheckthestatusofaRemoteService"
+     *      > http://community.abiquo.com/display/ABI20/RemoteServiceResource#RemoteServiceResource-
+     *      CheckthestatusofaRemoteService</a>
+     */
+    public boolean isAvailable()
+    {
+        // If the remote service can not be checked, assume it is available
+        return !getType().canBeChecked() ? true : context.getApi().getInfrastructureApi()
+            .isAvailable(target);
+    }
+
+    // Parent access
+
+    /**
+     * Retrieve the datacenter using this remotes service.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveadatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveadatacenter</a>
+     */
+    public Datacenter getDatacenter()
+    {
+        Integer datacenterId = target.getIdFromLink(ParentLinkName.DATACENTER);
+        DatacenterDto dto = context.getApi().getInfrastructureApi().getDatacenter(datacenterId);
+        datacenter = wrap(context, Datacenter.class, dto);
+        return datacenter;
+    }
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final Datacenter datacenter)
+    {
+        return new Builder(context, datacenter);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private Integer id;
+
+        private Datacenter datacenter;
+
+        private String ip;
+
+        private Integer port;
+
+        private RemoteServiceType type;
+
+        private Integer status = DEFAULT_STATUS;
+
+        // To be used only internally by the builder
+        private String uri;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final Datacenter datacenter)
+        {
+            super();
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            this.context = context;
+        }
+
+        public Builder datacenter(final Datacenter datacenter)
+        {
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            return this;
+        }
+
+        public Builder status(final int status)
+        {
+            this.status = status;
+            return this;
+        }
+
+        public Builder type(final RemoteServiceType type)
+        {
+            this.type = type;
+            return this;
+        }
+
+        public Builder ip(final String ip)
+        {
+            this.ip = ip;
+            return this;
+        }
+
+        public Builder port(final int port)
+        {
+            this.port = port;
+            return this;
+        }
+
+        private String generateUri(final String ip, final Integer port, final RemoteServiceType type)
+        {
+            return type.getDefaultProtocol() + ip + ":" + port + "/" + type.getServiceMapping();
+        }
+
+        public RemoteService build()
+        {
+            if (uri == null)
+            {
+                checkNotNull(ip, ValidationErrors.MISSING_REQUIRED_FIELD + "ip");
+                checkNotNull(type, ValidationErrors.MISSING_REQUIRED_FIELD + "type");
+
+                uri = generateUri(ip, port == null ? type.getDefaultPort() : port, type);
+            }
+
+            RemoteServiceDto dto = new RemoteServiceDto();
+            dto.setId(id);
+            dto.setType(type);
+            dto.setUri(uri);
+            dto.setStatus(status);
+            RemoteService remoteservice = new RemoteService(context, dto);
+            remoteservice.datacenter = datacenter;
+            return remoteservice;
+        }
+
+        public static Builder fromRemoteService(final RemoteService in)
+        {
+            Builder builder =
+                RemoteService.builder(in.context, in.getDatacenter()).status(in.getStatus())
+                    .type(in.getType());
+            builder.uri = in.getUri();
+            return builder;
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public RemoteServiceType getType()
+    {
+        return target.getType();
+    }
+
+    public int getStatus()
+    {
+        return target.getStatus();
+    }
+
+    public String getUri()
+    {
+        return target.getUri();
+    }
+
+    public void setStatus(final int status)
+    {
+        target.setStatus(status);
+    }
+
+    public void setType(final RemoteServiceType type)
+    {
+        target.setType(type);
+    }
+
+    public void setUri(final String uri)
+    {
+        target.setUri(uri);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "RemoteService [id=" + getId() + ", available=" + isAvailable() + ", type="
+            + getType() + ", status=" + getStatus() + ", uri" + getUri() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StorageDevice.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StorageDevice.java
new file mode 100644
index 0000000..de0360c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StorageDevice.java
@@ -0,0 +1,532 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.infrastructure.options.StoragePoolOptions;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolsDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link StorageDeviceDto}. The Storage Device Resource offers the
+ * functionality of managing the external storage.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/StorageDeviceResource">
+ *      http://community.abiquo.com/display/ABI20/StorageDeviceResource</a>
+ */
+@EnterpriseEdition
+public class StorageDevice extends DomainWrapper<StorageDeviceDto>
+{
+    /** The datacenter where the storage device is. */
+    private Datacenter datacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected StorageDevice(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final StorageDeviceDto target)
+    {
+        super(context, target);
+    }
+
+    /**
+     * Delete the storage device.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Deleteastoragedevice"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Deleteastoragedevice</a>
+     */
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteStorageDevice(target);
+        target = null;
+    }
+
+    /**
+     * Create a new storage device.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Createastoragedevice"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Createastoragedevice</a>
+     */
+    public void save()
+    {
+        target =
+            context.getApi().getInfrastructureApi()
+                .createStorageDevice(datacenter.unwrap(), target);
+    }
+
+    /**
+     * Update storage device information in the server with the data from this device.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Updateastoragedevice"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Updateastoragedevice</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateStorageDevice(target);
+    }
+
+    // Parent access
+
+    /**
+     * Retrieve the datacenter where this storage device is.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveadatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveadatacenter</a>
+     */
+    public Datacenter getDatacenter()
+    {
+        Integer datacenterId = target.getIdFromLink(ParentLinkName.DATACENTER);
+        DatacenterDto dto = context.getApi().getInfrastructureApi().getDatacenter(datacenterId);
+        datacenter = wrap(context, Datacenter.class, dto);
+        return datacenter;
+    }
+
+    // Children access
+
+    /**
+     * Retrieve the list of storage pools in this device (synchronized with the device).
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return Synchronized list of storage pools in this device.
+     */
+    public List<StoragePool> listRemoteStoragePools()
+    {
+        StoragePoolsDto storagePools =
+            context.getApi().getInfrastructureApi()
+                .listStoragePools(target, StoragePoolOptions.builder().sync(true).build());
+
+        List<StoragePool> storagePoolList =
+            wrap(context, StoragePool.class, storagePools.getCollection());
+
+        for (StoragePool storagePool : storagePoolList)
+        {
+            storagePool.storageDevice = this;
+        }
+
+        return storagePoolList;
+    }
+
+    /**
+     * Retrieve a filtered list of storage pools in this device (synchronized with the device).
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return Filtered synchronized list of storage pools in this device.
+     */
+    public List<StoragePool> listRemoteStoragePools(final Predicate<StoragePool> filter)
+    {
+        return Lists.newLinkedList(filter(listRemoteStoragePools(), filter));
+    }
+
+    /**
+     * Retrieve the first storage pool matching the filter within the list of storage pools in this
+     * device (synchronized with the device).
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return First storage pool (synchronized) matching the filter or <code>null</code> if there
+     *         is none.
+     */
+    public StoragePool findRemoteStoragePool(final Predicate<StoragePool> filter)
+    {
+        return Iterables.getFirst(filter(listRemoteStoragePools(), filter), null);
+    }
+
+    /**
+     * Retrieve the list of storage pools in this device from Abiquo database (may not be
+     * synchronized with the device).
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return Unsynchronized list of storage pools in this device.
+     */
+    public List<StoragePool> listStoragePools()
+    {
+        StoragePoolsDto storagePools =
+            context.getApi().getInfrastructureApi()
+                .listStoragePools(target, StoragePoolOptions.builder().sync(false).build());
+        return wrap(context, StoragePool.class, storagePools.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of storage pools in this device from Abiquo database (may not be
+     * synchronized with the device).
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return Filtered unsynchronized list of storage pools in this device.
+     */
+    public List<StoragePool> listStoragePools(final Predicate<StoragePool> filter)
+    {
+        return Lists.newLinkedList(filter(listStoragePools(), filter));
+    }
+
+    /**
+     * Retrieve the first storage pool matching the filter within the list of storage pools in this
+     * device (unsynchronized with the device).
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return First storage pool (unsynchronized) matching the filter or <code>null</code> if there
+     *         is none.
+     */
+    public StoragePool findStoragePool(final Predicate<StoragePool> filter)
+    {
+        return Iterables.getFirst(filter(listStoragePools(), filter), null);
+    }
+
+    /**
+     * Retrieve a single storage pool in this device from Abiquo database.
+     * 
+     * @param id Unique ID of the storage device in this datacenter.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievearegisteredpool"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievearegisteredpool</a>
+     * @return Storage pool with the given id or <code>null</code> if it does not exist.
+     */
+    public StoragePool getStoragePool(final String id)
+    {
+        StoragePoolDto storagePool =
+            context.getApi().getInfrastructureApi().getStoragePool(target, id);
+        return wrap(context, StoragePool.class, storagePool);
+    }
+
+    /**
+     * Retrieve the list of tiers in the datacenter using this device.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TierResource#TierResource-Retrievethelistoftiers"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/TierResource#TierResource-Retrievethelistoftiers
+     *      </a>
+     * @return List of tiers in the datacenter using this device.
+     */
+    public List<Tier> listTiersFromDatacenter()
+    {
+        DatacenterDto datacenter;
+
+        if (this.datacenter == null)
+        {
+            datacenter = new DatacenterDto();
+            datacenter.setId(target.getIdFromLink(ParentLinkName.DATACENTER));
+        }
+        else
+        {
+            datacenter = this.getDatacenter().unwrap();
+        }
+
+        TiersDto dto = context.getApi().getInfrastructureApi().listTiers(datacenter);
+        return DomainWrapper.wrap(context, Tier.class, dto.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of tiers in the datacenter using this device.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/TierResource#TierResource-Retrievethelistoftiers"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/TierResource#TierResource-Retrievethelistoftiers
+     *      </a>
+     * @return Filtered list of tiers in the datacenter using this device.
+     */
+    public List<Tier> listTiersFromDatacenter(final Predicate<Tier> filter)
+    {
+        return Lists.newLinkedList(filter(listTiersFromDatacenter(), filter));
+    }
+
+    /**
+     * Retrieve the first tier matching the filter within the list of tiers in the datacenter.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Retrievethelistofstoragedevices"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Retrievethelistofstoragedevices</a>
+     * @return First tier matching the filter or <code>null</code> if there is none.
+     */
+    public Tier findTierInDatacenter(final Predicate<Tier> filter)
+    {
+        return Iterables.getFirst(filter(listTiersFromDatacenter(), filter), null);
+    }
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Datacenter datacenter)
+    {
+        return new Builder(context, datacenter);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private Datacenter datacenter;
+
+        private String iscsiIp;
+
+        private Integer iscsiPort;
+
+        private String managementIp;
+
+        private Integer managementPort;
+
+        private String name;
+
+        private String password;
+
+        private String type;
+
+        private String username;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Datacenter datacenter)
+        {
+            super();
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            this.context = context;
+        }
+
+        public Builder datacenter(final Datacenter datacenter)
+        {
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            this.datacenter = datacenter;
+            return this;
+        }
+
+        public Builder iscsiIp(final String iscsiIp)
+        {
+            this.iscsiIp = iscsiIp;
+            return this;
+        }
+
+        public Builder iscsiPort(final int iscsiPort)
+        {
+            this.iscsiPort = iscsiPort;
+            return this;
+        }
+
+        public Builder password(final String password)
+        {
+            this.password = password;
+            return this;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public Builder managementPort(final int managementPort)
+        {
+            this.managementPort = managementPort;
+            return this;
+        }
+
+        public Builder managementIp(final String managementIp)
+        {
+            this.managementIp = managementIp;
+            return this;
+        }
+
+        public Builder type(final String type)
+        {
+            this.type = type;
+            return this;
+        }
+
+        public Builder username(final String username)
+        {
+            this.username = username;
+            return this;
+        }
+
+        public StorageDevice build()
+        {
+            StorageDeviceDto dto = new StorageDeviceDto();
+            dto.setIscsiIp(iscsiIp);
+            dto.setIscsiPort(iscsiPort);
+            dto.setManagementIp(managementIp);
+            dto.setManagementPort(managementPort);
+            dto.setName(name);
+            dto.setPassword(password);
+            dto.setStorageTechnology(type);
+            dto.setUsername(username);
+            StorageDevice storageDevice = new StorageDevice(context, dto);
+            storageDevice.datacenter = datacenter;
+            return storageDevice;
+        }
+
+        public static Builder fromStorageDevice(final StorageDevice in)
+        {
+            Builder builder =
+                StorageDevice.builder(in.context, in.getDatacenter()).iscsiIp(in.getIscsiIp())
+                    .iscsiPort(in.getIscsiPort()).managementIp(in.getManagementIp())
+                    .managementPort(in.getManagementPort()).name(in.getName())
+                    .password(in.getPassword()).type(in.getType()).username(in.getUsername());
+
+            return builder;
+        }
+    }
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getIscsiIp()
+    {
+        return target.getIscsiIp();
+    }
+
+    public int getIscsiPort()
+    {
+        return target.getIscsiPort();
+    }
+
+    public String getManagementIp()
+    {
+        return target.getManagementIp();
+    }
+
+    public int getManagementPort()
+    {
+        return target.getManagementPort();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getPassword()
+    {
+        return target.getPassword();
+    }
+
+    public String getType()
+    {
+        return target.getStorageTechnology();
+    }
+
+    public String getUsername()
+    {
+        return target.getUsername();
+    }
+
+    public void setIscsiIp(final String iscsiIp)
+    {
+        target.setIscsiIp(iscsiIp);
+    }
+
+    public void setIscsiPort(final int iscsiPort)
+    {
+        target.setIscsiPort(iscsiPort);
+    }
+
+    public void setManagementIp(final String managementIp)
+    {
+        target.setManagementIp(managementIp);
+    }
+
+    public void setManagementPort(final int managementPort)
+    {
+        target.setManagementPort(managementPort);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setPassword(final String password)
+    {
+        target.setPassword(password);
+    }
+
+    public void setType(final String type)
+    {
+        target.setStorageTechnology(type);
+    }
+
+    public void setUsername(final String username)
+    {
+        target.setUsername(username);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "StorageDevice [id=" + getId() + ", iscsiIp=" + getIscsiIp() + ", iscsiPort="
+            + getIscsiPort() + ", managementIp=" + getManagementIp() + ", managementPort="
+            + getManagementPort() + ", name=" + getName() + ", password=" + getPassword()
+            + ", type=" + getType() + ", user=" + getUsername() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StorageDeviceMetadata.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StorageDeviceMetadata.java
new file mode 100644
index 0000000..853b8d9
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StorageDeviceMetadata.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceMetadataDto;
+
+/**
+ * metadata describing a Storage Device.
+ * 
+ * @author Ignasi Barrera
+ */
+public class StorageDeviceMetadata extends DomainWrapper<StorageDeviceMetadataDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected StorageDeviceMetadata(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final StorageDeviceMetadataDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate methods
+
+    public String getType()
+    {
+        return target.getType();
+    }
+
+    public int getDefaultManagementPort()
+    {
+        return target.getDefaultManagementPort();
+    }
+
+    public int getDefaultIscsiPort()
+    {
+        return target.getDefaultIscsiPort();
+    }
+
+    public boolean requiresAuthentication()
+    {
+        return target.isRequiresAuthentication();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StoragePool.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StoragePool.java
new file mode 100644
index 0000000..579e0c4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/StoragePool.java
@@ -0,0 +1,376 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.config.Privilege;
+import org.jclouds.abiquo.domain.infrastructure.options.StoragePoolOptions;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to {@link StoragePoolDto}. The Storage Pool Resource allows you to
+ * perform any administrative task for remote pools.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/StoragePoolResource">
+ *      http://community.abiquo.com/display/ABI20/StoragePoolResource</a>
+ */
+@EnterpriseEdition
+public class StoragePool extends DomainWrapper<StoragePoolDto>
+{
+    /** The default value for the used space. */
+    private static final long DEFAULT_USED_SIZE = 0;
+
+    /** The datacenter where the storage device is. */
+    // Package protected to allow the storage device to be set automatically when discovering the
+    // pools in a device.
+    StorageDevice storageDevice;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected StoragePool(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final StoragePoolDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Delete the storage pool.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Deleteastoragepool"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Deleteastoragepool</a>
+     */
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteStoragePool(target);
+        target = null;
+    }
+
+    /**
+     * Create a storage pool. Create a storage pool means registering an existing storage pool
+     * obtained from {@link StorageDevice#listRemoteStoragePools} method and saving it. The Storage
+     * Pools must be associated with a Tier using {@link #setTier}.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Createastoragepoolwithatierlink"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Createastoragepoolwithatierlink</a>
+     */
+    public void save()
+    {
+        target =
+            context.getApi().getInfrastructureApi()
+                .createStoragePool(storageDevice.unwrap(), target);
+    }
+
+    /**
+     * Update pool information in the server with the data from this pool. Storage pool parameters
+     * cannot be updated by a user, so the parameters are only a representation of the remote pool.
+     * Although the whole storage pool entity is sent to the API in the update call, the only thing
+     * a user can change is the tier that the pool belongs to by calling {@link #setTier}.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Storage+Pool+Resource#StoragePoolResource-UpdateaStoragePool"
+     *      > http://community.abiquo.com/display/ABI20/Storage+Pool+Resource#StoragePoolResource-
+     *      UpdateaStoragePool</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateStoragePool(target);
+    }
+
+    public void refresh()
+    {
+        target =
+            context.getApi().getInfrastructureApi()
+                .refreshStoragePool(target, StoragePoolOptions.builder().sync(true).build());
+    }
+
+    /**
+     * Define the tier in which the pool will be added.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Createastoragepoolwithatierlink"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Createastoragepoolwithatierlink</a>
+     */
+    public void setTier(final Tier tier)
+    {
+        checkNotNull(tier, ValidationErrors.NULL_RESOURCE + Privilege.class);
+        checkNotNull(tier.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in " + Tier.class);
+
+        this.updateLink(target, ParentLinkName.TIER, tier.unwrap(), "edit");
+    }
+
+    // Parent access
+
+    /**
+     * Get the device where the pool belongs.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-Retrieveastoragedevice"
+     *      > http://community.abiquo.com/display/ABI20/StorageDeviceResource#StorageDeviceResource-
+     *      Retrieveastoragedevice</a>
+     */
+    public StorageDevice getStorageDevice()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.STORAGE_DEVICE),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.STORAGE_DEVICE);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<StorageDeviceDto> parser =
+            new ParseXMLWithJAXB<StorageDeviceDto>(utils.getXml(),
+                TypeLiteral.get(StorageDeviceDto.class));
+
+        return wrap(context, StorageDevice.class, parser.apply(response));
+    }
+
+    // Children access
+
+    /**
+     * Get the tier assigned to the pool. The storage pool needs to be persisted in Abiquo first.
+     * 
+     * @return The tier assinged to this storage pool.
+     */
+    public Tier getTier()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.TIER),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.TIER);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<TierDto> parser =
+            new ParseXMLWithJAXB<TierDto>(utils.getXml(), TypeLiteral.get(TierDto.class));
+
+        return wrap(context, Tier.class, parser.apply(response));
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final StorageDevice storageDevice)
+    {
+        return new Builder(context, storageDevice);
+    }
+
+    public static class Builder
+    {
+        private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        private StorageDevice storageDevice;
+
+        private Long availableSizeInMb;
+
+        // The enabled flag is still not used. It will be added when Abiquo includes anstorage
+        // allocator
+
+        // private Boolean enabled;
+
+        private String name;
+
+        private Long totalSizeInMb;
+
+        private Long usedSizeInMb = DEFAULT_USED_SIZE;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final StorageDevice storageDevice)
+        {
+            super();
+            checkNotNull(storageDevice, ValidationErrors.NULL_RESOURCE + StorageDevice.class);
+            this.storageDevice = storageDevice;
+            this.context = context;
+        }
+
+        public Builder storageDevice(final StorageDevice storageDevice)
+        {
+            checkNotNull(storageDevice, ValidationErrors.NULL_RESOURCE + StorageDevice.class);
+            this.storageDevice = storageDevice;
+            return this;
+        }
+
+        /**
+         * @deprecated This value is no longer used in Abiquo and will be removed in future
+         *             versions.
+         */
+        @Deprecated
+        public Builder availableSizeInMb(final long availableSizeInMb)
+        {
+            this.availableSizeInMb = availableSizeInMb;
+            return this;
+        }
+
+        public Builder name(final String name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        // The enabled flag is still not used. It will be added when Abiquo includes anstorage
+        // allocator
+
+        // public Builder enabled(final boolean enabled)
+        // {
+        // this.enabled = enabled;
+        // return this;
+        // }
+
+        public Builder totalSizeInMb(final long totalSizeInMb)
+        {
+            this.totalSizeInMb = totalSizeInMb;
+            if (availableSizeInMb == null)
+            {
+                availableSizeInMb = totalSizeInMb;
+            }
+            return this;
+        }
+
+        /**
+         * @deprecated This value is no longer used in Abiquo and will be removed in future
+         *             versions.
+         */
+        @Deprecated
+        public Builder usedSizeInMb(final long usedSizeInMb)
+        {
+            this.usedSizeInMb = usedSizeInMb;
+            return this;
+        }
+
+        public StoragePool build()
+        {
+            StoragePoolDto dto = new StoragePoolDto();
+            dto.setAvailableSizeInMb(availableSizeInMb);
+
+            // The enabled flag is still not used. It will be added when Abiquo includes anstorage
+            // allocator
+            // dto.setEnabled(enabled);
+
+            dto.setName(name);
+            dto.setTotalSizeInMb(totalSizeInMb);
+            dto.setUsedSizeInMb(usedSizeInMb);
+            StoragePool storagePool = new StoragePool(context, dto);
+            storagePool.storageDevice = storageDevice;
+            return storagePool;
+        }
+
+        public static Builder fromStoragePool(final StoragePool in)
+        {
+            Builder builder =
+                StoragePool.builder(in.context, in.getStorageDevice())
+                    .availableSizeInMb(in.getAvailableSizeInMb())/* .enabled(in.getEnabled()) */
+                    .totalSizeInMb(in.getTotalSizeInMb()).usedSizeInMb(in.getUsedSizeInMb());
+
+            return builder;
+        }
+    }
+
+    // Delegate methods
+
+    /**
+     * @deprecated This value is no longer used in Abiquo and will be removed in future versions.
+     */
+    @Deprecated
+    public long getAvailableSizeInMb()
+    {
+        return target.getAvailableSizeInMb();
+    }
+
+    // The enabled flag is still not used. It will be added when Abiquo includes anstorage
+    // allocator
+
+    // public boolean getEnabled()
+    // {
+    // return target.getEnabled();
+    // }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public long getTotalSizeInMb()
+    {
+        return target.getTotalSizeInMb();
+    }
+
+    /**
+     * @deprecated This value is no longer used in Abiquo and will be removed in future versions.
+     */
+    @Deprecated
+    public long getUsedSizeInMb()
+    {
+        return target.getUsedSizeInMb();
+    }
+
+    // The enabled flag is still not used. It will be added when Abiquo includes anstorage
+    // allocator
+
+    // public void setEnabled(final boolean enabled)
+    // {
+    // target.setEnabled(enabled);
+    // }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setTotalSizeInMb(final long totalSizeInMb)
+    {
+        target.setTotalSizeInMb(totalSizeInMb);
+    }
+
+    // Readonly property
+    public String getUUID()
+    {
+        return target.getIdStorage();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "StoragePool [name=" + getName() + ", totalSizeInMb=" + getTotalSizeInMb()
+            + ", uuid=" + getUUID() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Tier.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Tier.java
new file mode 100644
index 0000000..c39db98
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/Tier.java
@@ -0,0 +1,187 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolsDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds high level functionality to {@link TierDto}. The Tier Resource offers the functionality of
+ * managing the logic of QoS volume management. These are only logical levels of QoS and the real
+ * QoS (networking speed, volume replication, availability) must be configured manually in the
+ * infrastructure.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/TierResource">
+ *      http://community.abiquo.com/display/ABI20/TierResource</a>
+ */
+@EnterpriseEdition
+public class Tier extends DomainWrapper<TierDto>
+{
+    /** The datacenter where the tier belongs. */
+    private Datacenter datacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Tier(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final TierDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Update tier information in the server with the data from this tier.
+     * 
+     * @see API: <a
+     *      href="http://community.abiquo.com/display/ABI20/TierResource#TierResource-Updateatier">
+     *      http://community.abiquo.com/display/ABI20/TierResource#TierResource-Updateatier</a>
+     */
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateTier(target);
+    }
+
+    /**
+     * Retrieve the list of storage pools in this tier.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return List of storage pools in this tier.
+     */
+    public List<StoragePool> listStoragePools()
+    {
+        StoragePoolsDto storagePools =
+            context.getApi().getInfrastructureApi().listStoragePools(target);
+        return wrap(context, StoragePool.class, storagePools.getCollection());
+    }
+
+    /**
+     * Retrieve a filtered list of storage pools in this tier.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return Filtered list of storage pools in this tier.
+     */
+    public List<StoragePool> listStoragePools(final Predicate<StoragePool> filter)
+    {
+        return Lists.newLinkedList(filter(listStoragePools(), filter));
+    }
+
+    /**
+     * Retrieve the first storage pool matching the filter within the list of pools in this tier.
+     * 
+     * @param filter Filter to be applied to the list.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-Retrievestoragepools"
+     *      > http://community.abiquo.com/display/ABI20/StoragePoolResource#StoragePoolResource-
+     *      Retrievestoragepools</a>
+     * @return First storage pool matching the filter or <code>null</code> if there is none.
+     */
+    public StoragePool findStoragePool(final Predicate<StoragePool> filter)
+    {
+        return Iterables.getFirst(filter(listStoragePools(), filter), null);
+    }
+
+    // Parent access
+
+    /**
+     * Retrieve the datacenter where this tier is.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveadatacenter"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveadatacenter</a>
+     */
+    public Datacenter getDatacenter()
+    {
+        Integer datacenterId = target.getIdFromLink(ParentLinkName.DATACENTER);
+        DatacenterDto dto = context.getApi().getInfrastructureApi().getDatacenter(datacenterId);
+        datacenter = wrap(context, Datacenter.class, dto);
+        return datacenter;
+    }
+
+    // Delegate methods
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    public boolean getEnabled()
+    {
+        return target.getEnabled();
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public void setDescription(final String description)
+    {
+        target.setDescription(description);
+    }
+
+    public void setEnabled(final boolean enabled)
+    {
+        target.setEnabled(enabled);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Tier [id=" + getId() + ", description=" + getDescription() + ", enabled="
+            + getEnabled() + ", name=" + getName() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/DatacenterOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/DatacenterOptions.java
new file mode 100644
index 0000000..11998cb
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/DatacenterOptions.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query datacenters.
+ * 
+ * @author Francesc Montserrat
+ */
+public class DatacenterOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        DatacenterOptions options = new DatacenterOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private String ip;
+
+        public Builder ip(final String ip)
+        {
+            this.ip = ip;
+            return this;
+        }
+
+        public DatacenterOptions build()
+        {
+            DatacenterOptions options = new DatacenterOptions();
+            if (ip != null)
+            {
+                options.queryParameters.put("ip", ip);
+            }
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/IpmiOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/IpmiOptions.java
new file mode 100644
index 0000000..4bcc602
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/IpmiOptions.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query ipmi config.
+ * 
+ * @author scastro
+ */
+public class IpmiOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        IpmiOptions options = new IpmiOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private Integer port;
+
+        /**
+         * Set the optional hypervisor port.
+         */
+        public Builder port(final int port)
+        {
+            this.port = port;
+            return this;
+        }
+
+        public IpmiOptions build()
+        {
+            IpmiOptions options = new IpmiOptions();
+            if (port != null)
+            {
+                options.queryParameters.put("port", port.toString());
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/MachineOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/MachineOptions.java
new file mode 100644
index 0000000..f29db2d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/MachineOptions.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query machines.
+ * 
+ * @author Francesc Montserrat
+ */
+public class MachineOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        MachineOptions options = new MachineOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private Integer port;
+
+        private Boolean sync;
+
+        /**
+         * Set the optional hypervisor port.
+         */
+        public Builder port(final int port)
+        {
+            this.port = port;
+            return this;
+        }
+
+        /**
+         * Set the optional sync param.
+         */
+        public Builder sync(final boolean sync)
+        {
+            this.sync = sync;
+            return this;
+        }
+
+        public MachineOptions build()
+        {
+            MachineOptions options = new MachineOptions();
+            if (port != null)
+            {
+                options.queryParameters.put("port", port.toString());
+            }
+
+            if (sync != null)
+            {
+                options.queryParameters.put("sync", sync.toString());
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/StoragePoolOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/StoragePoolOptions.java
new file mode 100644
index 0000000..af546ef
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/infrastructure/options/StoragePoolOptions.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure.options;
+
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query storage pools.
+ * 
+ * @author Francesc Montserrat
+ */
+
+@EnterpriseEdition
+public class StoragePoolOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        StoragePoolOptions options = new StoragePoolOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private Boolean sync;
+
+        /**
+         * Set the optional sync param.
+         */
+        public Builder sync(final boolean sync)
+        {
+            this.sync = sync;
+            return this;
+        }
+
+        public StoragePoolOptions build()
+        {
+            StoragePoolOptions options = new StoragePoolOptions();
+            if (sync != null)
+            {
+                options.queryParameters.put("sync", sync.toString());
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/AbstractPublicIp.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/AbstractPublicIp.java
new file mode 100644
index 0000000..c3da0e3
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/AbstractPublicIp.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.network.AbstractInfrastructureIpDto;
+
+/**
+ * Adds generic high level functionality to {@link AbstractInfrastructureIpDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public abstract class AbstractPublicIp<T extends AbstractInfrastructureIpDto, N extends Network< ? >>
+    extends Ip<T, N>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected AbstractPublicIp(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final T target)
+    {
+        super(context, target);
+    }
+
+    // Delegate methods
+
+    public boolean isAvailable()
+    {
+        return target.isAvailable();
+    }
+
+    public boolean isQuarantine()
+    {
+        return target.isQuarantine();
+    }
+
+    public void setAvailable(final boolean available)
+    {
+        target.setAvailable(available);
+    }
+
+    public void setQuarantine(final boolean quarantine)
+    {
+        target.setQuarantine(quarantine);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/ExternalIp.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/ExternalIp.java
new file mode 100644
index 0000000..b881bf3
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/ExternalIp.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.network.ExternalIpDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds generic high level functionality to {@link ExternalIpDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class ExternalIp extends AbstractPublicIp<ExternalIpDto, ExternalNetwork>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected ExternalIp(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final ExternalIpDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    @Override
+    public ExternalNetwork getNetwork()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.EXTERNAL_NETWORK),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.EXTERNAL_NETWORK);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<VLANNetworkDto> parser =
+            new ParseXMLWithJAXB<VLANNetworkDto>(utils.getXml(),
+                TypeLiteral.get(VLANNetworkDto.class));
+
+        return wrap(context, ExternalNetwork.class, parser.apply(response));
+    }
+
+    @Override
+    public NetworkType getNetworkType()
+    {
+        return NetworkType.EXTERNAL;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "ExternalIp [networkType=" + getNetworkType() + ", available=" + isAvailable()
+            + ", quarantine=" + isQuarantine() + ", id=" + getId() + ", ip=" + getIp() + ", mac="
+            + getMac() + ", name=" + getName() + ", networkName=" + getNetworkName() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/ExternalNetwork.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/ExternalNetwork.java
new file mode 100644
index 0000000..8dfa92d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/ExternalNetwork.java
@@ -0,0 +1,259 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to external {@link VLANNetworkDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Public+Network+Resource">
+ *      http://community.abiquo.com/display/ABI20/Public+Network+Resource</a>
+ */
+@EnterpriseEdition
+public class ExternalNetwork extends Network<ExternalIp>
+{
+    /** The datacenter where the network belongs. */
+    private Datacenter datacenter;
+
+    /** The enterprise where the network belongs. */
+    private Enterprise enterprise;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected ExternalNetwork(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VLANNetworkDto target)
+    {
+        super(context, target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-DeleteanExternalNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -DeleteanExternalNetwork</a>
+     */
+    @Override
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteNetwork(target);
+        target = null;
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-CreateanewExternalNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -CreateanewExternalNetwork</a>
+     */
+    @Override
+    public void save()
+    {
+        this.addEnterpriseLink();
+        target =
+            context.getApi().getInfrastructureApi().createNetwork(datacenter.unwrap(), target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      " http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-UpdateanExternalNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -UpdateanExternalNetwork</a>
+     */
+    @Override
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateNetwork(target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+IPs+Resource#PublicIPsResource-ReturnthelistofIPsforaPublicNetwork"
+     *      > http://community.abiquo.com/display/ABI20/Public+IPs+Resource#PublicIPsResource-
+     *      ReturnthelistofIPsforaPublicNetwork</a>
+     */
+    @Override
+    public List<ExternalIp> listIps(final IpOptions options)
+    {
+        ExternalIpsDto ips =
+            context.getApi().getInfrastructureApi().listExternalIps(target, options);
+        return wrap(context, ExternalIp.class, ips.getCollection());
+    }
+
+    @Override
+    public ExternalIp getIp(final Integer id)
+    {
+        ExternalIpDto ip = context.getApi().getInfrastructureApi().getExternalIp(target, id);
+        return wrap(context, ExternalIp.class, ip);
+    }
+
+    // Parent access
+
+    public Enterprise getEnterprise()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.ENTERPRISE),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.ENTERPRISE);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<EnterpriseDto> parser =
+            new ParseXMLWithJAXB<EnterpriseDto>(utils.getXml(),
+                TypeLiteral.get(EnterpriseDto.class));
+
+        enterprise = wrap(context, Enterprise.class, parser.apply(response));
+        return enterprise;
+    }
+
+    public Datacenter getDatacenter()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.DATACENTER),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.DATACENTER);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<DatacenterDto> parser =
+            new ParseXMLWithJAXB<DatacenterDto>(utils.getXml(),
+                TypeLiteral.get(DatacenterDto.class));
+
+        datacenter = wrap(context, Datacenter.class, parser.apply(response));
+        return datacenter;
+    }
+
+    private void addEnterpriseLink()
+    {
+        checkNotNull(enterprise, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+        checkNotNull(enterprise.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in "
+            + Enterprise.class);
+
+        RESTLink link = enterprise.unwrap().getEditLink();
+        checkNotNull(link, ValidationErrors.MISSING_REQUIRED_LINK);
+
+        target.addLink(new RESTLink("enterprise", link.getHref()));
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Datacenter datacenter, final Enterprise enterprise)
+    {
+        return new Builder(context, datacenter, enterprise);
+    }
+
+    public static class Builder extends NetworkBuilder<Builder>
+    {
+        private Datacenter datacenter;
+
+        private Enterprise enterprise;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Datacenter datacenter, final Enterprise enterprise)
+        {
+            super(context);
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+            this.datacenter = datacenter;
+            this.enterprise = enterprise;
+            this.context = context;
+        }
+
+        public Builder datacenter(final Datacenter datacenter)
+        {
+            this.datacenter = datacenter;
+            return this;
+        }
+
+        public Builder enterprise(final Enterprise enterprise)
+        {
+            this.enterprise = enterprise;
+            return this;
+        }
+
+        public ExternalNetwork build()
+        {
+            VLANNetworkDto dto = new VLANNetworkDto();
+            dto.setName(name);
+            dto.setTag(tag);
+            dto.setGateway(gateway);
+            dto.setAddress(address);
+            dto.setMask(mask);
+            dto.setPrimaryDNS(primaryDNS);
+            dto.setSecondaryDNS(secondaryDNS);
+            dto.setSufixDNS(sufixDNS);
+            dto.setDefaultNetwork(defaultNetwork == null ? Boolean.FALSE : defaultNetwork);
+            dto.setUnmanaged(Boolean.FALSE);
+            dto.setType(NetworkType.EXTERNAL);
+
+            ExternalNetwork network = new ExternalNetwork(context, dto);
+            network.datacenter = datacenter;
+            network.enterprise = enterprise;
+
+            return network;
+        }
+
+        public static Builder fromExternalNetwork(final ExternalNetwork in)
+        {
+            return ExternalNetwork.builder(in.context, in.datacenter, in.enterprise)
+                .name(in.getName()).tag(in.getTag()).gateway(in.getGateway())
+                .address(in.getAddress()).mask(in.getMask()).primaryDNS(in.getPrimaryDNS())
+                .secondaryDNS(in.getSecondaryDNS()).sufixDNS(in.getSufixDNS())
+                .defaultNetwork(in.getDefaultNetwork());
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return "External " + super.toString();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Ip.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Ip.java
new file mode 100644
index 0000000..ef39edf
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Ip.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.server.core.infrastructure.network.AbstractIpDto;
+
+/**
+ * Adds generic high level functionality to {@link AbstractIpDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public abstract class Ip<T extends AbstractIpDto, N extends Network< ? >> extends DomainWrapper<T>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Ip(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final T target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    public abstract N getNetwork();
+
+    public abstract NetworkType getNetworkType();
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getIp()
+    {
+        return target.getIp();
+    }
+
+    public String getMac()
+    {
+        return target.getMac();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getNetworkName()
+    {
+        return target.getNetworkName();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Ip [id=" + getId() + ", ip=" + getIp() + ", mac=" + getMac() + ", name="
+            + getName() + ", networkName=" + getNetworkName() + "]";
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Network.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Network.java
new file mode 100644
index 0000000..8e700b6
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Network.java
@@ -0,0 +1,379 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.predicates.network.IpPredicates;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Adds generic high level functionality to {@link VLANNetworkDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public abstract class Network<T extends Ip< ? , ? >> extends DomainWrapper<VLANNetworkDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected Network(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VLANNetworkDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    public abstract void save();
+
+    public abstract void update();
+
+    public abstract void delete();
+
+    public abstract List<T> listIps(IpOptions options);
+
+    public abstract T getIp(Integer id);
+
+    public List<T> listIps()
+    {
+        // Disable pagination by default
+        return listIps(IpOptions.builder().disablePagination().build());
+    }
+
+    public List<T> listIps(final Predicate<T> filter)
+    {
+        return Lists.newLinkedList(filter(listIps(), filter));
+    }
+
+    public T findIp(final Predicate<T> filter)
+    {
+        return Iterables.getFirst(filter(listIps(), filter), null);
+    }
+
+    public List<T> listUnusedIps()
+    {
+        return listIps(IpPredicates.<T> notUsed());
+    }
+
+    public T findUnusedIp(final Predicate<T> filter)
+    {
+        return Iterables.getFirst(filter(listUnusedIps(), filter), null);
+    }
+
+    // Builder
+
+    public static class NetworkBuilder<T extends NetworkBuilder<T>>
+    {
+        protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+        protected String name;
+
+        protected Integer tag;
+
+        protected String gateway;
+
+        protected String address;
+
+        protected Integer mask;
+
+        protected String primaryDNS;
+
+        protected String secondaryDNS;
+
+        protected String sufixDNS;
+
+        protected Boolean defaultNetwork;
+
+        public NetworkBuilder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+        {
+            super();
+            this.context = context;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T name(final String name)
+        {
+            this.name = name;
+            return (T) this;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T tag(final Integer tag)
+        {
+            this.tag = tag;
+            return (T) this;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T gateway(final String gateway)
+        {
+            this.gateway = gateway;
+            return (T) this;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T address(final String address)
+        {
+            this.address = address;
+            return (T) this;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T mask(final int mask)
+        {
+            this.mask = mask;
+            return (T) this;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T primaryDNS(final String primaryDNS)
+        {
+            this.primaryDNS = primaryDNS;
+            return (T) this;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T secondaryDNS(final String secondaryDNS)
+        {
+            this.secondaryDNS = secondaryDNS;
+            return (T) this;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T sufixDNS(final String sufixDNS)
+        {
+            this.sufixDNS = sufixDNS;
+            return (T) this;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T defaultNetwork(final Boolean defaultNetwork)
+        {
+            this.defaultNetwork = defaultNetwork;
+            return (T) this;
+        }
+    }
+
+    public PrivateNetwork toPrivateNetwork()
+    {
+        checkArgument(target.getType().equals(NetworkType.INTERNAL),
+            ValidationErrors.INVALID_NETWORK_TYPE + target.getType());
+
+        return wrap(context, PrivateNetwork.class, target);
+
+    }
+
+    public ExternalNetwork toExternalNetwork()
+    {
+        checkArgument(target.getType().equals(NetworkType.EXTERNAL),
+            ValidationErrors.INVALID_NETWORK_TYPE + target.getType());
+
+        return wrap(context, ExternalNetwork.class, target);
+
+    }
+
+    public PublicNetwork toPublicNetwork()
+    {
+        checkArgument(target.getType().equals(NetworkType.PUBLIC),
+            ValidationErrors.INVALID_NETWORK_TYPE + target.getType());
+
+        return wrap(context, PublicNetwork.class, target);
+
+    }
+
+    public UnmanagedNetwork toUnmanagedNetwork()
+    {
+        checkArgument(target.getType().equals(NetworkType.UNMANAGED),
+            ValidationErrors.INVALID_NETWORK_TYPE + target.getType());
+
+        return wrap(context, UnmanagedNetwork.class, target);
+
+    }
+
+    // Delegate methods
+
+    public String getAddress()
+    {
+        return target.getAddress();
+    }
+
+    public Boolean getDefaultNetwork()
+    {
+        return target.getDefaultNetwork();
+    }
+
+    public String getGateway()
+    {
+        return target.getGateway();
+    }
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public Integer getMask()
+    {
+        return target.getMask();
+    }
+
+    public String getName()
+    {
+        return target.getName();
+    }
+
+    public String getPrimaryDNS()
+    {
+        return target.getPrimaryDNS();
+    }
+
+    public String getSecondaryDNS()
+    {
+        return target.getSecondaryDNS();
+    }
+
+    public String getSufixDNS()
+    {
+        return target.getSufixDNS();
+    }
+
+    public Integer getTag()
+    {
+        return target.getTag();
+    }
+
+    public NetworkType getType()
+    {
+        return target.getType();
+    }
+
+    public void setAddress(final String address)
+    {
+        target.setAddress(address);
+    }
+
+    public void setDefaultNetwork(final Boolean defaultNetwork)
+    {
+        target.setDefaultNetwork(defaultNetwork);
+    }
+
+    public void setGateway(final String gateway)
+    {
+        target.setGateway(gateway);
+    }
+
+    public void setMask(final Integer mask)
+    {
+        target.setMask(mask);
+    }
+
+    public void setName(final String name)
+    {
+        target.setName(name);
+    }
+
+    public void setPrimaryDNS(final String primaryDNS)
+    {
+        target.setPrimaryDNS(primaryDNS);
+    }
+
+    public void setSecondaryDNS(final String secondaryDNS)
+    {
+        target.setSecondaryDNS(secondaryDNS);
+    }
+
+    public void setSufixDNS(final String sufixDNS)
+    {
+        target.setSufixDNS(sufixDNS);
+    }
+
+    public void setTag(final Integer tag)
+    {
+        target.setTag(tag);
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Network [id=" + getId() + ", address=" + getAddress() + ", defaultNetwork="
+            + getDefaultNetwork() + ", gateway=" + getGateway() + ", mask=" + getMask() + ", name="
+            + getName() + ", primaryDNS=" + getPrimaryDNS() + ", secondaryDNS=" + getSecondaryDNS()
+            + ", suffixDNS=" + getSufixDNS() + ", tag=" + getTag() + ", type=" + getType() + "]";
+    }
+
+    public static Network< ? > wrapNetwork(
+        final RestContext<AbiquoApi, AbiquoAsyncApi> context, final VLANNetworkDto dto)
+    {
+        if (dto == null)
+        {
+            return null;
+        }
+
+        Network< ? > network = null;
+
+        switch (dto.getType())
+        {
+            case EXTERNAL:
+                network = wrap(context, ExternalNetwork.class, dto);
+                break;
+            case EXTERNAL_UNMANAGED:
+                // TODO: How do we manage External && unmanaged networks ?
+                throw new UnsupportedOperationException("EXTERNAL_UNMANAGED networks not supported yet");
+            case INTERNAL:
+                network = wrap(context, PrivateNetwork.class, dto);
+                break;
+            case PUBLIC:
+                network = wrap(context, PublicNetwork.class, dto);
+                break;
+            case UNMANAGED:
+                network = wrap(context, UnmanagedNetwork.class, dto);
+                break;
+        }
+
+        return network;
+    }
+
+    public static List<Network< ? >> wrapNetworks(
+        final RestContext<AbiquoApi, AbiquoAsyncApi> context, final List<VLANNetworkDto> dtos)
+    {
+        List<Network< ? >> networks = Lists.newLinkedList();
+        for (VLANNetworkDto dto : dtos)
+        {
+            networks.add(wrapNetwork(context, dto));
+        }
+        return networks;
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Nic.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Nic.java
new file mode 100644
index 0000000..78d7c3f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/Nic.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.network.NicDto;
+
+/**
+ * Adds high level functionality to {@link NicDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/VirtualMachineNetworkConfiguration">
+ *      http://community.abiquo.com/display/ABI20/VirtualMachineNetworkConfiguration</a>
+ */
+public class Nic extends DomainWrapper<NicDto>
+{
+    /**
+     * Constructor to be used only by the builder (if any).
+     */
+    protected Nic(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final NicDto target)
+    {
+        super(context, target);
+    }
+
+    // Parent access
+
+    // Delegate methods
+
+    public Integer getId()
+    {
+        return target.getId();
+    }
+
+    public String getIp()
+    {
+        return target.getIp();
+    }
+
+    public String getMac()
+    {
+        return target.getMac();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PrivateIp.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PrivateIp.java
new file mode 100644
index 0000000..1790551
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PrivateIp.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds generic high level functionality to {@link PrivateIpDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class PrivateIp extends Ip<PrivateIpDto, PrivateNetwork>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected PrivateIp(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final PrivateIpDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    @Override
+    public PrivateNetwork getNetwork()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.PRIVATE_NETWORK),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.PRIVATE_NETWORK);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<VLANNetworkDto> parser =
+            new ParseXMLWithJAXB<VLANNetworkDto>(utils.getXml(),
+                TypeLiteral.get(VLANNetworkDto.class));
+
+        return wrap(context, PrivateNetwork.class, parser.apply(response));
+    }
+
+    @Override
+    public NetworkType getNetworkType()
+    {
+        return NetworkType.INTERNAL;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "PrivateIp [networkType=" + getNetworkType() + ", id=" + getId() + ", ip=" + getIp()
+            + ", mac=" + getMac() + ", name=" + getName() + ", networkName=" + getNetworkName()
+            + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PrivateNetwork.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PrivateNetwork.java
new file mode 100644
index 0000000..4d4abed
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PrivateNetwork.java
@@ -0,0 +1,193 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+
+/**
+ * Adds high level functionality to private {@link VLANNetworkDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Private+Network+Resource">
+ *      http://community.abiquo.com/display/ABI20/Private+Network+Resource</a>
+ */
+public class PrivateNetwork extends Network<PrivateIp>
+{
+    /** The virtual datacenter where the network belongs. */
+    private VirtualDatacenter virtualDatacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected PrivateNetwork(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VLANNetworkDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource-DeleteaPrivateNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource
+     *      -DeleteaPrivateNetwork</a>
+     */
+    @Override
+    public void delete()
+    {
+        context.getApi().getCloudApi().deletePrivateNetwork(target);
+        target = null;
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource-CreateaPrivateNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource
+     *      -CreateaPrivateNetwork</a>
+     */
+    @Override
+    public void save()
+    {
+        target =
+            context.getApi().getCloudApi()
+                .createPrivateNetwork(virtualDatacenter.unwrap(), target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource-UpdateaPrivateNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource
+     *      -UpdateaPrivateNetwork</a>
+     */
+    @Override
+    public void update()
+    {
+        target = context.getApi().getCloudApi().updatePrivateNetwork(target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource-RetrievethelistofIPSofthePrivateNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Private+Network+Resource#PrivateNetworkResource
+     *      -RetrievethelistofIPSofthePrivateNetwork</a>
+     */
+    @Override
+    public List<PrivateIp> listIps(final IpOptions options)
+    {
+        PrivateIpsDto ips =
+            context.getApi().getCloudApi().listPrivateNetworkIps(target, options);
+        return wrap(context, PrivateIp.class, ips.getCollection());
+    }
+
+    // Override to apply the filter in the server side
+    @Override
+    public List<PrivateIp> listUnusedIps()
+    {
+        IpOptions options = IpOptions.builder().disablePagination().free(true).build();
+        PrivateIpsDto ips =
+            context.getApi().getCloudApi().listPrivateNetworkIps(target, options);
+        return wrap(context, PrivateIp.class, ips.getCollection());
+    }
+
+    @Override
+    public PrivateIp getIp(final Integer id)
+    {
+        PrivateIpDto ip = context.getApi().getCloudApi().getPrivateNetworkIp(target, id);
+        return wrap(context, PrivateIp.class, ip);
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        return new Builder(context);
+    }
+
+    public static class Builder extends NetworkBuilder<Builder>
+    {
+        private VirtualDatacenter virtualDatacenter;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+        {
+            super(context);
+            this.context = context;
+        }
+
+        public Builder virtualDatacenter(final VirtualDatacenter virtualDatacenter)
+        {
+            this.virtualDatacenter = virtualDatacenter;
+            return this;
+        }
+
+        public PrivateNetwork build()
+        {
+            VLANNetworkDto dto = new VLANNetworkDto();
+            dto.setName(name);
+            dto.setTag(tag);
+            dto.setGateway(gateway);
+            dto.setAddress(address);
+            dto.setMask(mask);
+            dto.setPrimaryDNS(primaryDNS);
+            dto.setSecondaryDNS(secondaryDNS);
+            dto.setSufixDNS(sufixDNS);
+            dto.setDefaultNetwork(defaultNetwork);
+            dto.setUnmanaged(false);
+            dto.setType(NetworkType.INTERNAL);
+
+            PrivateNetwork network = new PrivateNetwork(context, dto);
+            network.virtualDatacenter = virtualDatacenter;
+
+            return network;
+        }
+
+        public static Builder fromPrivateNetwork(final PrivateNetwork in)
+        {
+            return PrivateNetwork.builder(in.context).name(in.getName()).tag(in.getTag())
+                .gateway(in.getGateway()).address(in.getAddress()).mask(in.getMask())
+                .primaryDNS(in.getPrimaryDNS()).secondaryDNS(in.getSecondaryDNS())
+                .sufixDNS(in.getSufixDNS()).defaultNetwork(in.getDefaultNetwork())
+                .virtualDatacenter(in.virtualDatacenter);
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Private " + super.toString();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PublicIp.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PublicIp.java
new file mode 100644
index 0000000..e2f0ebd
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PublicIp.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds generic high level functionality to {@link PublicIpDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class PublicIp extends AbstractPublicIp<PublicIpDto, PublicNetwork>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected PublicIp(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final PublicIpDto target)
+    {
+        super(context, target);
+    }
+
+    @Override
+    public PublicNetwork getNetwork()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.PUBLIC_NETWORK),
+                ValidationErrors.MISSING_REQUIRED_LINK + ParentLinkName.PUBLIC_NETWORK);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<VLANNetworkDto> parser =
+            new ParseXMLWithJAXB<VLANNetworkDto>(utils.getXml(),
+                TypeLiteral.get(VLANNetworkDto.class));
+
+        return wrap(context, PublicNetwork.class, parser.apply(response));
+    }
+
+    @Override
+    public NetworkType getNetworkType()
+    {
+        return NetworkType.PUBLIC;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "PublicIp [networkType=" + getNetworkType() + ", available=" + isAvailable()
+            + ", quarantine=" + isQuarantine() + ", id=" + getId() + ", ip=" + getIp() + ", mac="
+            + getMac() + ", name=" + getName() + ", networkName=" + getNetworkName() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PublicNetwork.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PublicNetwork.java
new file mode 100644
index 0000000..554166d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/PublicNetwork.java
@@ -0,0 +1,215 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to public {@link VLANNetworkDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Public+Network+Resource">
+ *      http://community.abiquo.com/display/ABI20/Public+Network+Resource</a>
+ */
+@EnterpriseEdition
+public class PublicNetwork extends Network<PublicIp>
+{
+    /** The datacenter where the network belongs. */
+    private Datacenter datacenter;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected PublicNetwork(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VLANNetworkDto target)
+    {
+        super(context, target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-DeleteaPublicNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -DeleteaPublicNetwork</a>
+     */
+    @Override
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteNetwork(target);
+        target = null;
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-CreateanewPublicNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -CreateanewPublicNetwork</a>
+     */
+    @Override
+    public void save()
+    {
+        target =
+            context.getApi().getInfrastructureApi().createNetwork(datacenter.unwrap(), target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-UpdateaPublicNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -UpdateaPublicNetwork</a>
+     */
+    @Override
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateNetwork(target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+IPs+Resource#PublicIPsResource-ReturnthelistofIPsforaPublicNetwork"
+     *      > http://community.abiquo.com/display/ABI20/Public+IPs+Resource#PublicIPsResource-
+     *      ReturnthelistofIPsforaPublicNetwork</a>
+     */
+    @Override
+    public List<PublicIp> listIps(final IpOptions options)
+    {
+        PublicIpsDto ips =
+            context.getApi().getInfrastructureApi().listPublicIps(target, options);
+        return wrap(context, PublicIp.class, ips.getCollection());
+    }
+
+    @Override
+    public PublicIp getIp(final Integer id)
+    {
+        PublicIpDto ip = context.getApi().getInfrastructureApi().getPublicIp(target, id);
+        return wrap(context, PublicIp.class, ip);
+    }
+
+    // Parent access
+
+    public Datacenter getDatacenter()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.DATACENTER),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.DATACENTER);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<DatacenterDto> parser =
+            new ParseXMLWithJAXB<DatacenterDto>(utils.getXml(),
+                TypeLiteral.get(DatacenterDto.class));
+
+        datacenter = wrap(context, Datacenter.class, parser.apply(response));
+        return datacenter;
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Datacenter datacenter)
+    {
+        return new Builder(context, datacenter);
+    }
+
+    public static class Builder extends NetworkBuilder<Builder>
+    {
+        private Datacenter datacenter;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Datacenter datacenter)
+        {
+            super(context);
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+            this.datacenter = datacenter;
+            this.context = context;
+        }
+
+        public Builder datacenter(final Datacenter datacenter)
+        {
+            this.datacenter = datacenter;
+            return this;
+        }
+
+        public PublicNetwork build()
+        {
+            VLANNetworkDto dto = new VLANNetworkDto();
+            dto.setName(name);
+            dto.setTag(tag);
+            dto.setGateway(gateway);
+            dto.setAddress(address);
+            dto.setMask(mask);
+            dto.setPrimaryDNS(primaryDNS);
+            dto.setSecondaryDNS(secondaryDNS);
+            dto.setSufixDNS(sufixDNS);
+            dto.setDefaultNetwork(defaultNetwork);
+            dto.setUnmanaged(false);
+            dto.setType(NetworkType.PUBLIC);
+
+            PublicNetwork network = new PublicNetwork(context, dto);
+            network.datacenter = datacenter;
+
+            return network;
+        }
+
+        public static Builder fromPublicNetwork(final PublicNetwork in)
+        {
+            return PublicNetwork.builder(in.context, in.datacenter).name(in.getName())
+                .tag(in.getTag()).gateway(in.getGateway()).address(in.getAddress())
+                .mask(in.getMask()).primaryDNS(in.getPrimaryDNS())
+                .secondaryDNS(in.getSecondaryDNS()).sufixDNS(in.getSufixDNS())
+                .defaultNetwork(in.getDefaultNetwork());
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Public " + super.toString();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/UnmanagedIp.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/UnmanagedIp.java
new file mode 100644
index 0000000..c6fb0cd
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/UnmanagedIp.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds generic high level functionality to {@link UnmanagedIpDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class UnmanagedIp extends AbstractPublicIp<UnmanagedIpDto, UnmanagedNetwork>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected UnmanagedIp(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final UnmanagedIpDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    @Override
+    public UnmanagedNetwork getNetwork()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.UNMANAGED_NETWORK),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.UNMANAGED_NETWORK);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<VLANNetworkDto> parser =
+            new ParseXMLWithJAXB<VLANNetworkDto>(utils.getXml(),
+                TypeLiteral.get(VLANNetworkDto.class));
+
+        return wrap(context, UnmanagedNetwork.class, parser.apply(response));
+    }
+
+    @Override
+    public NetworkType getNetworkType()
+    {
+        return NetworkType.UNMANAGED;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "UnmanagedIp [networkType=" + getNetworkType() + ", available=" + isAvailable()
+            + ", quarantine=" + isQuarantine() + ", id=" + getId() + ", ip=" + getIp() + ", mac="
+            + getMac() + ", name=" + getName() + ", networkName=" + getNetworkName() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/UnmanagedNetwork.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/UnmanagedNetwork.java
new file mode 100644
index 0000000..81c0ddd
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/UnmanagedNetwork.java
@@ -0,0 +1,260 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Adds high level functionality to external {@link VLANNetworkDto}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/Public+Network+Resource">
+ *      http://community.abiquo.com/display/ABI20/Public+Network+Resource</a>
+ */
+@EnterpriseEdition
+public class UnmanagedNetwork extends Network<UnmanagedIp>
+{
+    /** The datacenter where the network belongs. */
+    private Datacenter datacenter;
+
+    /** The enterprise where the network belongs. */
+    private Enterprise enterprise;
+
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected UnmanagedNetwork(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final VLANNetworkDto target)
+    {
+        super(context, target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-DeleteanUnmanagedNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -DeleteanUnmanagedNetwork</a>
+     */
+    @Override
+    public void delete()
+    {
+        context.getApi().getInfrastructureApi().deleteNetwork(target);
+        target = null;
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-CreateanewUnmanagedNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -CreateanewUnmanagedNetwork</a>
+     */
+    @Override
+    public void save()
+    {
+        this.addEnterpriseLink();
+        target =
+            context.getApi().getInfrastructureApi().createNetwork(datacenter.unwrap(), target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource-UpdateanUnmanagedNetwork"
+     *      >
+     *      http://community.abiquo.com/display/ABI20/Public+Network+Resource#PublicNetworkResource
+     *      -UpdateanUnmanagedNetwork</a>
+     */
+    @Override
+    public void update()
+    {
+        target = context.getApi().getInfrastructureApi().updateNetwork(target);
+    }
+
+    /**
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Public+IPs+Resource#PublicIPsResource-ReturnthelistofIPsforaPublicNetwork"
+     *      > http://community.abiquo.com/display/ABI20/Public+IPs+Resource#PublicIPsResource-
+     *      ReturnthelistofIPsforaPublicNetwork</a>
+     */
+    @Override
+    public List<UnmanagedIp> listIps(final IpOptions options)
+    {
+        UnmanagedIpsDto ips =
+            context.getApi().getInfrastructureApi().listUnmanagedIps(target, options);
+        return wrap(context, UnmanagedIp.class, ips.getCollection());
+    }
+
+    @Override
+    public UnmanagedIp getIp(final Integer id)
+    {
+        UnmanagedIpDto ip = context.getApi().getInfrastructureApi().getUnmanagedIp(target, id);
+        return wrap(context, UnmanagedIp.class, ip);
+    }
+
+    // Parent access
+
+    public Enterprise getEnterprise()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.ENTERPRISE),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.ENTERPRISE);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<EnterpriseDto> parser =
+            new ParseXMLWithJAXB<EnterpriseDto>(utils.getXml(),
+                TypeLiteral.get(EnterpriseDto.class));
+
+        enterprise = wrap(context, Enterprise.class, parser.apply(response));
+        return enterprise;
+    }
+
+    public Datacenter getDatacenter()
+    {
+        RESTLink link =
+            checkNotNull(target.searchLink(ParentLinkName.DATACENTER),
+                ValidationErrors.MISSING_REQUIRED_LINK + " " + ParentLinkName.DATACENTER);
+
+        ExtendedUtils utils = (ExtendedUtils) context.getUtils();
+        HttpResponse response = utils.getAbiquoHttpClient().get(link);
+
+        ParseXMLWithJAXB<DatacenterDto> parser =
+            new ParseXMLWithJAXB<DatacenterDto>(utils.getXml(),
+                TypeLiteral.get(DatacenterDto.class));
+
+        datacenter = wrap(context, Datacenter.class, parser.apply(response));
+        return datacenter;
+    }
+
+    private void addEnterpriseLink()
+    {
+        checkNotNull(enterprise, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+        checkNotNull(enterprise.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in "
+            + Enterprise.class);
+
+        RESTLink link = enterprise.unwrap().searchLink("edit");
+
+        checkNotNull(link, ValidationErrors.MISSING_REQUIRED_LINK);
+
+        target.addLink(new RESTLink("enterprise", link.getHref()));
+    }
+
+    // Builder
+
+    public static Builder builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final Datacenter datacenter, final Enterprise enterprise)
+    {
+        return new Builder(context, datacenter, enterprise);
+    }
+
+    public static class Builder extends NetworkBuilder<Builder>
+    {
+        private Datacenter datacenter;
+
+        private Enterprise enterprise;
+
+        public Builder(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+            final Datacenter datacenter, final Enterprise enterprise)
+        {
+            super(context);
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Datacenter.class);
+            checkNotNull(datacenter, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+            this.datacenter = datacenter;
+            this.enterprise = enterprise;
+            this.context = context;
+        }
+
+        public Builder datacenter(final Datacenter datacenter)
+        {
+            this.datacenter = datacenter;
+            return this;
+        }
+
+        public Builder enterprise(final Enterprise enterprise)
+        {
+            this.enterprise = enterprise;
+            return this;
+        }
+
+        public UnmanagedNetwork build()
+        {
+            VLANNetworkDto dto = new VLANNetworkDto();
+            dto.setName(name);
+            dto.setTag(tag);
+            dto.setGateway(gateway);
+            dto.setAddress(address);
+            dto.setMask(mask);
+            dto.setPrimaryDNS(primaryDNS);
+            dto.setSecondaryDNS(secondaryDNS);
+            dto.setSufixDNS(sufixDNS);
+            dto.setDefaultNetwork(defaultNetwork);
+            dto.setUnmanaged(true);
+            dto.setType(NetworkType.UNMANAGED);
+
+            UnmanagedNetwork network = new UnmanagedNetwork(context, dto);
+            network.datacenter = datacenter;
+            network.enterprise = enterprise;
+
+            return network;
+        }
+
+        public static Builder fromUnmanagedNetwork(final UnmanagedNetwork in)
+        {
+            return UnmanagedNetwork.builder(in.context, in.datacenter, in.enterprise)
+                .name(in.getName()).tag(in.getTag()).gateway(in.getGateway())
+                .address(in.getAddress()).mask(in.getMask()).primaryDNS(in.getPrimaryDNS())
+                .secondaryDNS(in.getSecondaryDNS()).sufixDNS(in.getSufixDNS())
+                .defaultNetwork(in.getDefaultNetwork());
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Unmanaged " + super.toString();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/options/IpOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/options/IpOptions.java
new file mode 100644
index 0000000..d44191b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/options/IpOptions.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network.options;
+
+import org.jclouds.abiquo.domain.options.search.FilterOptions.BaseFilterOptionsBuilder;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * Available options to query ips.
+ * 
+ * @author Francesc Montserrat
+ */
+public class IpOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        IpOptions options = new IpOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder extends BaseFilterOptionsBuilder<Builder>
+    {
+        private Boolean free;
+
+        public Builder free(final boolean free)
+        {
+            this.free = free;
+            return this;
+        }
+
+        public IpOptions build()
+        {
+            IpOptions options = new IpOptions();
+
+            if (free != null)
+            {
+                options.queryParameters.put("free", String.valueOf(free));
+            }
+
+            return addFilterOptions(options);
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/options/NetworkOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/options/NetworkOptions.java
new file mode 100644
index 0000000..f97d182
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/network/options/NetworkOptions.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.abiquo.model.enumerator.NetworkType;
+
+/**
+ * Available options to query networks.
+ * 
+ * @author Francesc Montserrat
+ */
+public class NetworkOptions extends BaseHttpRequestOptions
+{
+    public static Builder builder()
+    {
+        return new Builder();
+    }
+
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        NetworkOptions options = new NetworkOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static class Builder
+    {
+        private NetworkType type;
+
+        private Boolean all;
+
+        public Builder type(final NetworkType type)
+        {
+            this.type = type;
+            return this;
+        }
+
+        public Builder all(final boolean all)
+        {
+            this.all = all;
+            return this;
+        }
+
+        public NetworkOptions build()
+        {
+            NetworkOptions options = new NetworkOptions();
+
+            if (type != null)
+            {
+                options.queryParameters.put("type", String.valueOf(type));
+            }
+
+            if (all != null)
+            {
+                options.queryParameters.put("all", String.valueOf(all));
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/options/search/FilterOptions.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/options/search/FilterOptions.java
new file mode 100644
index 0000000..34b6269
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/options/search/FilterOptions.java
@@ -0,0 +1,143 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.options.search;
+
+import org.jclouds.abiquo.domain.options.search.reference.OrderBy;
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * Available options to filter and pagination methods.
+ * 
+ * @author Francesc Montserrat
+ */
+public class FilterOptions extends BaseHttpRequestOptions
+{
+    @Override
+    protected Object clone() throws CloneNotSupportedException
+    {
+        FilterOptions options = new FilterOptions();
+        options.queryParameters.putAll(queryParameters);
+        return options;
+    }
+
+    public static FilterOptionsBuilder builder()
+    {
+        return new FilterOptionsBuilder();
+    }
+
+    public static class FilterOptionsBuilder extends BaseFilterOptionsBuilder<FilterOptionsBuilder>
+    {
+        public FilterOptions build()
+        {
+            FilterOptions options = new FilterOptions();
+            return super.addFilterOptions(options);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static class BaseFilterOptionsBuilder<T extends BaseFilterOptionsBuilder<T>>
+    {
+        protected Integer startWith;
+
+        protected Integer limit;
+
+        protected OrderBy by;
+
+        protected String has;
+
+        protected Boolean asc;
+
+        public T startWith(final int startWith)
+        {
+            this.startWith = startWith;
+            return (T) this;
+        }
+
+        public T has(final String has)
+        {
+            this.has = has;
+            return (T) this;
+        }
+
+        public T limit(final int limit)
+        {
+            this.limit = limit;
+            return (T) this;
+        }
+
+        public T orderBy(final OrderBy by)
+        {
+            this.by = by;
+            return (T) this;
+        }
+
+        public T ascendant(final boolean asc)
+        {
+            this.asc = asc;
+            return (T) this;
+        }
+
+        public T descendant(final boolean desc)
+        {
+            this.asc = !desc;
+            return (T) this;
+        }
+
+        public T disablePagination()
+        {
+            this.limit = 0;
+            return (T) this;
+        }
+
+        protected <O extends BaseHttpRequestOptions> O addFilterOptions(final O options)
+        {
+            Multimap<String, String> queryParameters = options.buildQueryParameters();
+
+            if (startWith != null)
+            {
+                queryParameters.put("startwith", startWith.toString());
+            }
+
+            if (limit != null)
+            {
+                queryParameters.put("limit", limit.toString());
+            }
+
+            if (has != null)
+            {
+                queryParameters.put("has", has);
+            }
+
+            if (by != null)
+            {
+                queryParameters.put("by", by.getValue());
+            }
+
+            if (asc != null)
+            {
+                queryParameters.put("asc", asc.toString());
+            }
+
+            return options;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/options/search/reference/OrderBy.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/options/search/reference/OrderBy.java
new file mode 100644
index 0000000..75fede5
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/options/search/reference/OrderBy.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.options.search.reference;
+
+/**
+ * Available fields to order search results.
+ * 
+ * @author Francesc Montserrat
+ * @author Ignasi Barrera
+ */
+public enum OrderBy
+{
+    NAME("name"), ID("id"), VIRTUALDATACENTER("virtualdatacenter"), VIRTUALMACHINE("virtualmachine"), VIRTUALAPPLIANCE(
+        "virtualappliance"), TIER("tier"), TOTALSIZE("totalsize"), STATE("state");
+
+    public String value;
+
+    public String getValue()
+    {
+        return value;
+    }
+
+    private OrderBy(final String value)
+    {
+        this.value = value;
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncJob.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncJob.java
new file mode 100644
index 0000000..19d47fe
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncJob.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.task;
+
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.task.Job.JobState;
+import com.abiquo.server.core.task.Job.JobType;
+import com.abiquo.server.core.task.JobDto;
+
+/**
+ * Adds generic high level functionality to {JobDto}.
+ * 
+ * @author Francesc Montserrat
+ */
+public class AsyncJob extends DomainWrapper<JobDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected AsyncJob(final RestContext<AbiquoApi, AbiquoAsyncApi> context, final JobDto target)
+    {
+        super(context, target);
+    }
+
+    // Delegate methods
+
+    public String getDescription()
+    {
+        return target.getDescription();
+    }
+
+    public String getId()
+    {
+        return target.getId();
+    }
+
+    public JobState getRollbackState()
+    {
+        return target.getRollbackState();
+    }
+
+    public JobState getState()
+    {
+        return target.getState();
+    }
+
+    public long getTimestamp()
+    {
+        return target.getTimestamp();
+    }
+
+    public JobType getType()
+    {
+        return target.getType();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "AsyncJob [id=" + getId() + ", description=" + getDescription() + ", rollbackState="
+            + getRollbackState() + ", state=" + getState() + ", timestamp=" + getTimestamp()
+            + ", type=" + getType() + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncTask.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncTask.java
new file mode 100644
index 0000000..7e1f02f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncTask.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.task;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.task.TaskDto;
+import com.abiquo.server.core.task.enums.TaskState;
+import com.abiquo.server.core.task.enums.TaskType;
+
+/**
+ * Adds generic high level functionality to {TaskDto}.
+ * 
+ * @author Francesc Montserrat
+ */
+public class AsyncTask extends DomainWrapper<TaskDto>
+{
+    /**
+     * Constructor to be used only by the builder.
+     */
+    protected AsyncTask(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final TaskDto target)
+    {
+        super(context, target);
+    }
+
+    // Domain operations
+
+    /**
+     * Refresh the state of the task.
+     */
+    public void refresh()
+    {
+        RESTLink self =
+            checkNotNull(target.searchLink("self"), ValidationErrors.MISSING_REQUIRED_LINK + "self");
+
+        target = context.getApi().getTaskApi().getTask(self);
+    }
+
+    // Children access
+
+    /**
+     * Get the individual jobs that compose the current task.
+     */
+    public List<AsyncJob> getJobs()
+    {
+        return wrap(context, AsyncJob.class, target.getJobs().getCollection());
+    }
+
+    // Delegate methods
+
+    public String getOwnerId()
+    {
+        return target.getOwnerId();
+    }
+
+    public TaskState getState()
+    {
+        return target.getState();
+    }
+
+    public String getTaskId()
+    {
+        return target.getTaskId();
+    }
+
+    public long getTimestamp()
+    {
+        return target.getTimestamp();
+    }
+
+    public TaskType getType()
+    {
+        return target.getType();
+    }
+
+    public String getUserId()
+    {
+        return target.getUserId();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "AsyncTask [taskId=" + getTaskId() + ", ownerId=" + getOwnerId() + ", timestamp="
+            + getTimestamp() + ", userId=" + getUserId() + ", state=" + getState() + ", type="
+            + getType() + "]";
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/util/LinkUtils.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/util/LinkUtils.java
new file mode 100644
index 0000000..485a413
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/domain/util/LinkUtils.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.util;
+
+import static com.google.common.collect.Iterables.filter;
+
+import java.util.List;
+
+import org.jclouds.abiquo.predicates.LinkPredicates;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.google.common.collect.Lists;
+
+/**
+ * Utility method to work with {@link RESTLink} objects.
+ * 
+ * @author Ignasi Barrera
+ */
+public class LinkUtils
+{
+    /**
+     * Get the link that points to the current resource.
+     * 
+     * @param dto The target dto.
+     * @return The link to the current resource.
+     */
+    public static RESTLink getSelfLink(final SingleResourceTransportDto dto)
+    {
+        RESTLink link = dto.searchLink("edit");
+        return link == null ? dto.searchLink("self") : link;
+    }
+
+    /**
+     * Filter the given link list and return only the links that point to a NIC.
+     * 
+     * @param links The list with the links to filter.
+     * @return A lsit with all links taht point to a NIC.
+     */
+    public static List<RESTLink> filterNicLinks(final List<RESTLink> links)
+    {
+        return Lists.newLinkedList(filter(links, LinkPredicates.isNic()));
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/events/handlers/AbstractEventHandler.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/handlers/AbstractEventHandler.java
new file mode 100644
index 0000000..74621ac
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/handlers/AbstractEventHandler.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.events.handlers;
+
+import javax.annotation.Resource;
+
+import org.jclouds.abiquo.events.monitor.MonitorEvent;
+import org.jclouds.logging.Logger;
+
+/**
+ * Base class for all {@link MonitorEvent} handlers.
+ * 
+ * @author Ignasi Barrera
+ */
+public abstract class AbstractEventHandler<T>
+{
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    /**
+     * Checks if the current handler must handle the dispatched event.
+     * 
+     * @param event The event being dispatched.
+     * @return Boolean indicating if the event must be handled by the current handler.
+     */
+    protected abstract boolean handles(MonitorEvent<T> event);
+
+    // Public getters and setters to allow non-guice code to set the appropriate logger
+
+    public Logger getLogger()
+    {
+        return logger;
+    }
+
+    public void setLogger(final Logger logger)
+    {
+        this.logger = logger;
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/events/handlers/BlockingEventHandler.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/handlers/BlockingEventHandler.java
new file mode 100644
index 0000000..7973fe3
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/handlers/BlockingEventHandler.java
@@ -0,0 +1,169 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.events.handlers;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import org.jclouds.abiquo.events.monitor.MonitorEvent;
+import org.jclouds.logging.Logger;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * An event handler that blocks the thread until all monitored objects have been finished being
+ * watched.
+ * <p>
+ * Due to <a href="http://code.google.com/p/guava-libraries/issues/detail?id=783">Guava Issue
+ * 786</a> {@link #handle(MonitorEvent)} is marked <code>final</code>to avoid having duplicate
+ * events.
+ * 
+ * @author Ignasi Barrera
+ * @param <T> The monitored object.
+ */
+public class BlockingEventHandler<T> extends AbstractEventHandler<T>
+{
+    /** The signal used to lock the thread. */
+    @VisibleForTesting
+    CountDownLatch completeSignal;
+
+    /**
+     * The objects being locked.
+     * <p>
+     * This class handles events in a thread safe way. Otherwise this collections should be
+     * synchronised.
+     */
+    protected List<T> lockedObjects;
+
+    public BlockingEventHandler(final T... lockedObjects)
+    {
+        this(Logger.NULL, lockedObjects);
+    }
+
+    public BlockingEventHandler(final Logger logger, final T... lockedObjects)
+    {
+        super();
+        checkArgument(checkNotNull(lockedObjects, "lockedObjects").length > 0,
+            "must provide at least one object");
+        this.logger = checkNotNull(logger, "logger");
+        this.lockedObjects = Lists.newArrayList(lockedObjects);
+        this.logger.debug("created BlockingEventHandler locking %s objects", lockedObjects.length);
+    }
+
+    @Override
+    protected boolean handles(final MonitorEvent<T> event)
+    {
+        logger.debug("checking if %s event on %s must be handled by %s", event.getType(),
+            event.getTarget(), this);
+        boolean handles = lockedObjects.contains(event.getTarget());
+        logger.debug("%s event on %s must %sbe handled", event.getType(), event.getTarget(),
+            handles ? "" : "not ");
+        return handles;
+    }
+
+    /**
+     * Handles the dispatched event in a thread safe way.
+     * <p>
+     * Due to <a href="http://code.google.com/p/guava-libraries/issues/detail?id=783">Guava Issue
+     * 786</a> {@link #handle(MonitorEvent)} is marked <code>final</code>to avoid having duplicate
+     * events.
+     * 
+     * @see {@link #doBeforeRelease(MonitorEvent)}
+     */
+    @Subscribe
+    public final void handle(final MonitorEvent<T> event)
+    {
+        if (handles(event))
+        {
+            logger.debug("handling %s", event);
+
+            try
+            {
+                doBeforeRelease(event);
+            }
+            finally
+            {
+                // Always release the lock, even if the handler code fails
+                release(event.getTarget());
+            }
+        }
+    }
+
+    /**
+     * Blocks the thread until all locked objects have been released.
+     */
+    public void lock()
+    {
+        // When invoking the lock, it is possible that all events have
+        // already been consumed. If there are no objects to monitor,
+        // just ignore the lock.
+        if (!lockedObjects.isEmpty())
+        {
+            try
+            {
+                completeSignal = new CountDownLatch(lockedObjects.size());
+                logger.debug("creating lock for %s object(s)", lockedObjects.size());
+                completeSignal.await();
+            }
+            catch (InterruptedException ex)
+            {
+                Throwables.propagate(ex);
+            }
+        }
+        else
+        {
+            logger.debug("there is nothing to watch. Ignoring lock.");
+        }
+    }
+
+    /**
+     * Releases the lock on the given object.
+     */
+    protected void release(final T target)
+    {
+        logger.debug("releasing %s", target);
+        lockedObjects.remove(target);
+
+        // The completeSignal might be null if the events have been consumed
+        // before acquiring the lock
+        if (completeSignal != null)
+        {
+            completeSignal.countDown();
+            logger.debug("releasing lock for %s. %s remaining objects", target,
+                completeSignal.getCount());
+        }
+    }
+
+    /**
+     * Convenience method to bypass the <a
+     * href="http://code.google.com/p/guava-libraries/issues/detail?id=783">Guava Issue 786</a> that
+     * forces the subscriber method to be <code>final</code>.
+     */
+    protected void doBeforeRelease(final MonitorEvent<T> event)
+    {
+        // Let subclasses may override it to customize behavior
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/CompletedEvent.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/CompletedEvent.java
new file mode 100644
index 0000000..3bfbb59
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/CompletedEvent.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.events.monitor;
+
+/**
+ * Event dispatched when a monitoring job completes without error.
+ * 
+ * @author Ignasi Barrera
+ */
+public class CompletedEvent<T> extends MonitorEvent<T>
+{
+    public CompletedEvent(final T target)
+    {
+        super(MonitorEvent.Type.COMPLETED, target);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/FailedEvent.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/FailedEvent.java
new file mode 100644
index 0000000..e2be976
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/FailedEvent.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.events.monitor;
+
+/**
+ * Event dispatched when a monitoring job completes with errors.
+ * 
+ * @author Ignasi Barrera
+ */
+public class FailedEvent<T> extends MonitorEvent<T>
+{
+    public FailedEvent(final T target)
+    {
+        super(MonitorEvent.Type.FAILED, target);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/MonitorEvent.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/MonitorEvent.java
new file mode 100644
index 0000000..e03dd79
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/MonitorEvent.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.events.monitor;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * base class for all monitor events.
+ * 
+ * @author Ignasi Barrera
+ */
+public class MonitorEvent<T>
+{
+    /**
+     * The type of the event.
+     */
+    public static enum Type
+    {
+        COMPLETED, FAILED, TIMEOUT;
+    }
+
+    /** The type of the event. */
+    private Type type;
+
+    /** The target object being monitored. */
+    private T target;
+
+    public MonitorEvent(final Type type, final T target)
+    {
+        super();
+        this.type = checkNotNull(type, "type");
+        this.target = checkNotNull(target, "target");
+    }
+
+    public Type getType()
+    {
+        return type;
+    }
+
+    public void setType(final Type type)
+    {
+        this.type = type;
+    }
+
+    public T getTarget()
+    {
+        return target;
+    }
+
+    public void setTarget(final T target)
+    {
+        this.target = target;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "MonitorEvent [type=" + type + ", target=" + target + "]";
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/TimeoutEvent.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/TimeoutEvent.java
new file mode 100644
index 0000000..6effde8
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/events/monitor/TimeoutEvent.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.events.monitor;
+
+/**
+ * Event dispatched when a monitoring job times out.
+ * 
+ * @author Ignasi Barrera
+ */
+public class TimeoutEvent<T> extends MonitorEvent<T>
+{
+    public TimeoutEvent(final T target)
+    {
+        super(MonitorEvent.Type.TIMEOUT, target);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/AdminApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/AdminApi.java
new file mode 100644
index 0000000..e01e6c6
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/AdminApi.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.PrivilegesDto;
+import com.abiquo.server.core.enterprise.RoleDto;
+import com.abiquo.server.core.enterprise.RolesDto;
+import com.abiquo.server.core.enterprise.UserDto;
+
+/**
+ * Provides synchronous access to Abiquo Admin API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see AdminAsyncApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface AdminApi
+{
+    /* ********************** User ********************** */
+
+    /**
+     * Get the information of the current user.
+     * 
+     * @return The information of the current user.
+     */
+    UserDto getCurrentUser();
+
+    /* ********************** Role ********************** */
+
+    /**
+     * List global roles.
+     * 
+     * @return The list of global Roles.
+     */
+    RolesDto listRoles();
+
+    /**
+     * List enterprise roles.
+     * 
+     * @return The list of Roles for the given enterprise.
+     */
+    RolesDto listRoles(EnterpriseDto enterprise);
+
+    /**
+     * Retrieves the role of the given user.
+     * 
+     * @param user The user.
+     * @return The role of the user.
+     */
+    RoleDto getRole(UserDto user);
+
+    /**
+     * Get the given role.
+     * 
+     * @param roleId The id of the role.
+     * @return The role or <code>null</code> if it does not exist.
+     */
+    RoleDto getRole(Integer roleId);
+
+    /**
+     * Deletes an existing role.
+     * 
+     * @param role The role to delete.
+     */
+    void deleteRole(final RoleDto role);
+
+    /**
+     * Updates an existing role.
+     * 
+     * @param role The new attributes for the role.
+     * @return The updated role.
+     */
+    RoleDto updateRole(RoleDto role);
+
+    /**
+     * Create a new role.
+     * 
+     * @param role The role to be created.
+     * @return The created role.
+     */
+    RoleDto createRole(RoleDto role);
+
+    /**
+     * Get privileges of the given role.
+     * 
+     * @param role The role.
+     * @return The list of privileges.
+     */
+    PrivilegesDto listPrivileges(RoleDto role);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/AdminAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/AdminAsyncApi.java
new file mode 100644
index 0000000..3209c72
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/AdminAsyncApi.java
@@ -0,0 +1,153 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.abiquo.binders.BindToXMLPayloadAndPath;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.functions.enterprise.ParseEnterpriseId;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.ParamParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.PrivilegesDto;
+import com.abiquo.server.core.enterprise.RoleDto;
+import com.abiquo.server.core.enterprise.RolesDto;
+import com.abiquo.server.core.enterprise.UserDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Abiquo Admin API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see AdminApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+public interface AdminAsyncApi
+{
+    /*********************** Login ***********************/
+
+    /**
+     * @see AdminApi#getCurrentUser()
+     */
+    @GET
+    @Path("/login")
+    @Consumes(UserDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UserDto> getCurrentUser();
+
+    /*********************** Role ***********************/
+
+    /**
+     * @see AdminApi#listRoles()
+     */
+    @GET
+    @Path("/admin/roles")
+    @Consumes(RolesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RolesDto> listRoles();
+
+    /**
+     * @see AdminApi#listRoles(Enterprise enterprise)
+     */
+    @GET
+    @Path("/admin/roles")
+    @Consumes(RolesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RolesDto> listRoles(
+        @QueryParam("identerprise") @ParamParser(ParseEnterpriseId.class) final EnterpriseDto enterprise);
+
+    /**
+     * @see AdminApi#getRole(UserDto)
+     */
+    @GET
+    @Consumes(RoleDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<RoleDto> getRole(
+        @EndpointLink("role") @BinderParam(BindToPath.class) UserDto user);
+
+    /**
+     * @see AdminApi#getRole(Integer)
+     */
+    @GET
+    @Path("/admin/roles/{role}")
+    @Consumes(RoleDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<RoleDto> getRole(@PathParam("role") Integer roleId);
+
+    /**
+     * @see AdminApi#deleteRole(RoleDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteRole(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) RoleDto role);
+
+    /**
+     * @see AdminApi#updateRole(RoleDto)
+     */
+    @PUT
+    @Produces(RoleDto.BASE_MEDIA_TYPE)
+    @Consumes(RoleDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RoleDto> updateRole(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) RoleDto role);
+
+    /**
+     * @see AdminApi#createRole(RoleDto)
+     */
+    @POST
+    @Path("/admin/roles")
+    @Produces(RoleDto.BASE_MEDIA_TYPE)
+    @Consumes(RoleDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RoleDto> createRole(@BinderParam(BindToXMLPayload.class) RoleDto role);
+
+    /**
+     * @see AdminApi#listPrivileges(RoleDto)
+     */
+    @GET
+    @Consumes(PrivilegesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PrivilegesDto> listPrivileges(
+        @EndpointLink("privileges") @BinderParam(BindToPath.class) RoleDto role);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/CloudApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/CloudApi.java
new file mode 100644
index 0000000..e6ef57f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/CloudApi.java
@@ -0,0 +1,680 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.cloud.options.VirtualApplianceOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualDatacenterOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineTemplateOptions;
+import org.jclouds.abiquo.domain.cloud.options.VolumeOptions;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualApplianceStateDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.cloud.VirtualDatacentersDto;
+import com.abiquo.server.core.cloud.VirtualMachineDto;
+import com.abiquo.server.core.cloud.VirtualMachineStateDto;
+import com.abiquo.server.core.cloud.VirtualMachineTaskDto;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpsDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.abiquo.server.core.infrastructure.network.VMNetworkConfigurationsDto;
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+import com.abiquo.server.core.infrastructure.storage.DisksManagementDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.abiquo.server.core.infrastructure.storage.VolumesManagementDto;
+
+/**
+ * Provides synchronous access to Abiquo Cloud API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see CloudAsyncApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface CloudApi
+{
+    /*********************** Virtual Datacenter ***********************/
+
+    /**
+     * List all virtual datacenters.
+     * 
+     * @param options Optional query params.
+     * @return The list of Datacenters.
+     */
+    VirtualDatacentersDto listVirtualDatacenters(VirtualDatacenterOptions options);
+
+    /**
+     * Get the given virtual datacenter.
+     * 
+     * @param virtualDatacenterId The id of the virtual datacenter.
+     * @return The virtual datacenter or <code>null</code> if it does not exist.
+     */
+    VirtualDatacenterDto getVirtualDatacenter(Integer virtualDatacenterId);
+
+    /**
+     * Create a new virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter to be created.
+     * @param datacenter Datacenter where the virtualdatacenter will be deployed.
+     * @param enterprise Enterprise of the virtual datacenter.
+     * @return The created virtual datacenter.
+     */
+    VirtualDatacenterDto createVirtualDatacenter(VirtualDatacenterDto virtualDatacenter,
+        DatacenterDto datacenter, EnterpriseDto enterprise);
+
+    /**
+     * Updates an existing virtual datacenter.
+     * 
+     * @param virtualDatacenter The new attributes for the virtual datacenter.
+     * @return The updated virtual datacenter.
+     */
+    VirtualDatacenterDto updateVirtualDatacenter(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * Deletes an existing virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter to delete.
+     */
+    void deleteVirtualDatacenter(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * List all available templates for the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @return The list of available templates.
+     */
+    VirtualMachineTemplatesDto listAvailableTemplates(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * List all available templates for the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param options Filtering options.
+     * @return The list of available templates.
+     */
+    VirtualMachineTemplatesDto listAvailableTemplates(VirtualDatacenterDto virtualDatacenter,
+        VirtualMachineTemplateOptions options);
+
+    /**
+     * List all available ips to purchase in the datacenter by the virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param options Filtering options.
+     * @return The list of available ips.
+     */
+    PublicIpsDto listAvailablePublicIps(VirtualDatacenterDto virtualDatacenter, IpOptions options);
+
+    /**
+     * List all purchased public ip addresses in the virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param options Filtering options.
+     * @return The list of purchased ips.
+     */
+    PublicIpsDto listPurchasedPublicIps(VirtualDatacenterDto virtualDatacenter, IpOptions options);
+
+    /**
+     * Purchase a public IP.
+     * 
+     * @param ip The public ip address to purchase.
+     * @return The purchased public ip.
+     */
+    PublicIpDto purchasePublicIp(PublicIpDto publicIp);
+
+    /**
+     * Release a public IP.
+     * 
+     * @param ip The public ip address to purchase.
+     * @return The release public ip.
+     */
+    PublicIpDto releasePublicIp(PublicIpDto publicIp);
+
+    /**
+     * List the storage tiers available for the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @return The storage tiers available to the given virtual datacenter.
+     */
+    @EnterpriseEdition
+    TiersDto listStorageTiers(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * Get the storage tier from the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param The id of the storage tier.
+     * @return The storage tiers available to the given virtual datacenter.
+     */
+    @EnterpriseEdition
+    TierDto getStorageTier(VirtualDatacenterDto virtualDatacenter, Integer tierId);
+
+    /*********************** Private Network ***********************/
+
+    /**
+     * Get the default network of the virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @return The default network of the virtual datacenter.
+     */
+    VLANNetworkDto getDefaultNetwork(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * Set the default network of the virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param network The default network.
+     */
+    void setDefaultNetwork(VirtualDatacenterDto virtualDatacenter, VLANNetworkDto network);
+
+    /**
+     * List all private networks for a virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @return The list of private networks for the virtual datacenter.
+     */
+    VLANNetworksDto listPrivateNetworks(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * Get the given private network from the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param virtualApplianceId The id of the private network.
+     * @return The private network or <code>null</code> if it does not exist.
+     */
+    VLANNetworkDto getPrivateNetwork(VirtualDatacenterDto virtualDatacenter,
+        Integer privateNetworkId);
+
+    /**
+     * Create a new private network in a virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param privateNetwork The private network to be created.
+     * @return The created private network.
+     */
+    VLANNetworkDto createPrivateNetwork(final VirtualDatacenterDto virtualDatacenter,
+        final VLANNetworkDto privateNetwork);
+
+    /**
+     * Updates an existing private network from the given virtual datacenter.
+     * 
+     * @param privateNetwork The new attributes for the private network.
+     * @return The updated private network.
+     */
+    VLANNetworkDto updatePrivateNetwork(VLANNetworkDto privateNetwork);
+
+    /**
+     * Deletes an existing private network.
+     * 
+     * @param privateNetwork The private network to delete.
+     */
+    void deletePrivateNetwork(VLANNetworkDto privateNetwork);
+
+    /*********************** Private Network IPs ***********************/
+
+    /**
+     * List all ips for a private network.
+     * 
+     * @param network The private network.
+     * @return The list of ips for the private network.
+     */
+    PrivateIpsDto listPrivateNetworkIps(VLANNetworkDto network);
+
+    /**
+     * List all ips for a private network with options.
+     * 
+     * @param network The private network.
+     * @param options Filtering options.
+     * @return The list of ips for the private network.
+     */
+    PrivateIpsDto listPrivateNetworkIps(VLANNetworkDto network, IpOptions options);
+
+    /**
+     * Get the requested ip from the given private network.
+     * 
+     * @param network The private network.
+     * @param ipId The id of the ip to get.
+     * @return The requested ip.
+     */
+    PrivateIpDto getPrivateNetworkIp(VLANNetworkDto network, Integer ipId);
+
+    /*********************** Virtual Appliance ***********************/
+
+    /**
+     * List all virtual appliance for a virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @return The list of virtual appliances for the virtual datacenter.
+     */
+    VirtualAppliancesDto listVirtualAppliances(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * Get the given virtual appliance from the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param virtualApplianceId The id of the virtual appliance.
+     * @return The virtual appliance or <code>null</code> if it does not exist.
+     */
+    VirtualApplianceDto getVirtualAppliance(VirtualDatacenterDto virtualDatacenter,
+        Integer virtualApplianceId);
+
+    /**
+     * Create a new virtual appliance in a virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param virtualAppliance The virtual appliance to be created.
+     * @return The created virtual appliance.
+     */
+    VirtualApplianceDto createVirtualAppliance(VirtualDatacenterDto virtualDatacenter,
+        VirtualApplianceDto virtualAppliance);
+
+    /**
+     * Updates an existing virtual appliance from the given virtual datacenter.
+     * 
+     * @param virtualAppliance The new attributes for the virtual appliance.
+     * @return The updated virtual appliance.
+     */
+    VirtualApplianceDto updateVirtualAppliance(VirtualApplianceDto virtualAppliance);
+
+    /**
+     * Deletes an existing virtual appliance.
+     * 
+     * @param virtualAppliance The virtual appliance to delete.
+     */
+    void deleteVirtualAppliance(VirtualApplianceDto virtualAppliance);
+
+    /**
+     * Deletes an existing virtual appliance.
+     * 
+     * @param virtualAppliance The virtual appliance to delete.
+     * @param options The options to customize the delete operation (e.g. Force delete).
+     */
+    void deleteVirtualAppliance(VirtualApplianceDto virtualAppliance,
+        VirtualApplianceOptions options);
+
+    /**
+     * Deploy a virtual appliance.
+     * 
+     * @param virtualAppliance The virtual appliance to deploy
+     * @param options the extra options for the deploy process.
+     * @return Response message to the deploy request.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    AcceptedRequestDto<String> deployVirtualAppliance(VirtualApplianceDto virtualAppliance,
+        VirtualMachineTaskDto options);
+
+    /**
+     * Undeploy a virtual appliance.
+     * 
+     * @param virtualAppliance The virtual appliance to undeploy
+     * @param options the extra options for the undeploy process.
+     * @return Response message to the undeploy request.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    AcceptedRequestDto<String> undeployVirtualAppliance(VirtualApplianceDto virtualAppliance,
+        VirtualMachineTaskDto options);
+
+    /**
+     * Get the state of the given virtual appliance.
+     * 
+     * @param virtualAppliance The given virtual appliance.
+     * @return The state of the given virtual appliance.
+     */
+    VirtualApplianceStateDto getVirtualApplianceState(VirtualApplianceDto virtualAppliance);
+
+    /*********************** Virtual Machine ***********************/
+
+    /**
+     * List all virtual machines for a virtual appliance.
+     * 
+     * @param virtualAppliance The virtual appliance.
+     * @return The list of virtual machines for the virtual appliance.
+     */
+    VirtualMachinesWithNodeExtendedDto listVirtualMachines(VirtualApplianceDto virtualAppliance);
+
+    /**
+     * List all virtual machines for a virtual appliance.
+     * 
+     * @param virtualAppliance The virtual appliance.
+     * @param options The options to filter the list of virtual machines.
+     * @return The list of virtual machines for the virtual appliance.
+     */
+    VirtualMachinesWithNodeExtendedDto listVirtualMachines(VirtualApplianceDto virtualAppliance,
+        VirtualMachineOptions options);
+
+    /**
+     * Get the given virtual machine from the given virtual machine.
+     * 
+     * @param virtualAppliance The virtual appliance.
+     * @param virtualMachineId The id of the virtual machine.
+     * @return The virtual machine or <code>null</code> if it does not exist.
+     */
+    VirtualMachineWithNodeExtendedDto getVirtualMachine(VirtualApplianceDto virtualAppliance,
+        Integer virtualMachineId);
+
+    /**
+     * Create a new virtual machine in a virtual appliance.
+     * 
+     * @param virtualAppliance The virtual appliance.
+     * @param virtualMachine The virtual machine to be created.
+     * @return The created virtual machine.
+     */
+    VirtualMachineWithNodeExtendedDto createVirtualMachine(VirtualApplianceDto virtualAppliance,
+        VirtualMachineWithNodeExtendedDto virtualMachine);
+
+    /**
+     * Deletes an existing virtual machine.
+     * 
+     * @param virtualMachine The virtual machine to delete.
+     */
+    void deleteVirtualMachine(VirtualMachineDto virtualMachine);
+
+    /**
+     * Updates an existing virtual machine from the given virtual appliance.
+     * 
+     * @param virtualMachine The new attributes for the virtual machine.
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    AcceptedRequestDto<String> updateVirtualMachine(VirtualMachineWithNodeExtendedDto virtualMachine);
+
+    /**
+     * Updates an existing virtual machine from the given virtual appliance.
+     * 
+     * @param virtualMachine The new attributes for the virtual machine.
+     * @param options The update options.
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    AcceptedRequestDto<String> updateVirtualMachine(
+        VirtualMachineWithNodeExtendedDto virtualMachine, VirtualMachineOptions options);
+
+    /**
+     * Changes the state an existing virtual machine.
+     * 
+     * @param virtualMachine The given virtual machine.
+     * @param state The new state.
+     * @return The task reference.
+     */
+    AcceptedRequestDto<String> changeVirtualMachineState(VirtualMachineDto virtualMachine,
+        VirtualMachineStateDto state);
+
+    /**
+     * Get the state of the given virtual machine.
+     * 
+     * @param virtualMachine The given virtual machine.
+     * @return The state of the given virtual machine.
+     */
+    VirtualMachineStateDto getVirtualMachineState(VirtualMachineDto virtualMachine);
+
+    /**
+     * Deploy a virtual machine with task options.
+     * 
+     * @param virtualMachine The virtual machine to deploy.
+     * @param options extra deploy options.
+     * @return Response message to the deploy request.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    AcceptedRequestDto<String> deployVirtualMachine(VirtualMachineDto virtualMachine,
+        VirtualMachineTaskDto options);
+
+    /**
+     * Uneploy a virtual machine with task options.
+     * 
+     * @param virtualMachine The virtual machine to undeploy.
+     * @param options extra deploy unoptions.
+     * @return Response message to the undeploy request.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    AcceptedRequestDto<String> undeployVirtualMachine(VirtualMachineDto virtualMachine,
+        VirtualMachineTaskDto options);
+
+    /**
+     * List all available network configurations for a virtual machine.
+     * 
+     * @param virtualMachine The virtual machine.
+     * @return The list of network configurations.
+     */
+    VMNetworkConfigurationsDto listNetworkConfigurations(VirtualMachineDto virtualMachine);
+
+    /**
+     * Sets the gateway network to be used by this virtual machine.
+     * 
+     * @param virtualMachine The virtual machine.
+     * @param network The gateway network to use.
+     */
+    void setGatewayNetwork(final VirtualMachineDto virtualMachine, final VLANNetworkDto network);
+
+    /**
+     * Reboot a virtual machine.
+     * 
+     * @param virtualMachine The virtual machine to reboot.
+     * @return Response message to the reset request.
+     */
+    AcceptedRequestDto<String> rebootVirtualMachine(VirtualMachineDto virtualMachine);
+
+    /******************* Virtual Machine Template ***********************/
+
+    /**
+     * Get the template of a virtual machine.
+     * 
+     * @param virtualMachine The given virtual machine.
+     * @return The template of the given virtual machine.
+     */
+    VirtualMachineTemplateDto getVirtualMachineTemplate(VirtualMachineDto virtualMachine);
+
+    /**
+     * Get the volumes attached to the given virtual machine.
+     * 
+     * @param virtualMachine The virtual machine.
+     * @return The volumes attached to the given virtual machine.
+     */
+    VolumesManagementDto listAttachedVolumes(VirtualMachineDto virtualMachine);
+
+    /**
+     * Detach all volumes from the given virtual machine.
+     * <p>
+     * If the virtual machine is deployed, the operation will be executed asynchronously.
+     * 
+     * @param virtualMachine The virtual machine.
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    AcceptedRequestDto<String> detachAllVolumes(VirtualMachineDto virtualMachine);
+
+    /**
+     * Replaces the current volumes attached to the virtual machine with the given ones.
+     * <p>
+     * If the virtual machine is deployed, the operation will be executed asynchronously.
+     * 
+     * @param virtualMachine The virtual machine.
+     * @param options virtual machine parameters
+     * @param volumes The new volumes for the virtual machine.
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    AcceptedRequestDto<String> replaceVolumes(VirtualMachineDto virtualMachine,
+        VirtualMachineOptions options, VolumeManagementDto... volumes);
+
+    /**
+     * List all hard disks attached to the given virtual machine.
+     * 
+     * @param virtualMachine The virtual machine.
+     * @return The hard disks attached to the virtual machine.
+     */
+    DisksManagementDto listAttachedHardDisks(VirtualMachineDto virtualMachine);
+
+    /**
+     * Detach all hard disks from the given virtual machine.
+     * <p>
+     * If the virtual machine is deployed, the operation will be executed asynchronously.
+     * 
+     * @param virtualMachine The virtual machine.
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    AcceptedRequestDto<String> detachAllHardDisks(VirtualMachineDto virtualMachine);
+
+    /**
+     * Replaces the current hard disks attached to the virtual machine with the given ones.
+     * <p>
+     * If the virtual machine is deployed, the operation will be executed asynchronously.
+     * 
+     * @param virtualMachine The virtual machine.
+     * @param hardDisks The new hard disks for the virtual machine.
+     * @return The task reference or <code>null</code> if the operation completed synchronously.
+     */
+    AcceptedRequestDto<String> replaceHardDisks(VirtualMachineDto virtualMachine,
+        DiskManagementDto... hardDisks);
+
+    /*********************** Hard disks ***********************/
+
+    /**
+     * List all hard disks in the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @return The hard disks in the virtual datacenter.
+     */
+    DisksManagementDto listHardDisks(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * Get the hard disk with the given id in the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param diskId The id of the hard disk to get.
+     * @return The requested hard disk or <code>null</code> if it does not exist.
+     */
+    DiskManagementDto getHardDisk(VirtualDatacenterDto virtualDatacenter, Integer diskId);
+
+    /**
+     * Creates a new hard disk in the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter where the hard disk will be created.
+     * @param hardDisk The hard disk to create.
+     * @return The created hard disk.
+     */
+    DiskManagementDto createHardDisk(VirtualDatacenterDto virtualDatacenter,
+        DiskManagementDto hardDisk);
+
+    /**
+     * Deletes the given hard disk.
+     * 
+     * @param hardDisk The hard disk to delete.
+     */
+    void deleteHardDisk(DiskManagementDto hardDisk);
+
+    /*********************** Volumes ***********************/
+
+    /**
+     * List all volumes in the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @return The volumes in the virtual datacenter.
+     */
+    @EnterpriseEdition
+    VolumesManagementDto listVolumes(VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * List all volumes in the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param options Optional parameters to filter the volume list.
+     * @return The volumes in the virtual datacenter.
+     */
+    @EnterpriseEdition
+    VolumesManagementDto listVolumes(VirtualDatacenterDto virtualDatacenter, VolumeOptions options);
+
+    /**
+     * Get a volume from the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter.
+     * @param volumeId The id of the volume to get.
+     * @return The volume or <code>null</code> if it does not exist.
+     */
+    @EnterpriseEdition
+    VolumeManagementDto getVolume(VirtualDatacenterDto virtualDatacenter, Integer volumeId);
+
+    /**
+     * Creates a volume in the given virtual datacenter.
+     * 
+     * @param virtualDatacenter The virtual datacenter where the volume will be created.
+     * @param volume The volume to create. This volume dto must contain a link to the tier where the
+     *            volume should be created.
+     * @return The created volume.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    VolumeManagementDto createVolume(VirtualDatacenterDto virtualDatacenter,
+        VolumeManagementDto volume);
+
+    /**
+     * Modifies the given volume.
+     * <p>
+     * If the virtual machine is deployed and the size of the volume is changed, then an
+     * asynchronous task will be generated to refresh the resources of the virtual machine in the
+     * hypervisor.
+     * 
+     * @param volume The volume to modify.
+     * @return The task reference or <code>null</code> if no task was generated.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    AcceptedRequestDto<String> updateVolume(VolumeManagementDto volume);
+
+    /**
+     * Delete the given volume.
+     * 
+     * @param volume The volume to delete.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    void deleteVolume(VolumeManagementDto volume);
+
+    /**
+     * Moves the given volume to a new virtual datacenter.
+     * <p>
+     * The Abiquo API will return a 301 (Moved Permanently), so redirects must be enabled to make
+     * this method succeed.
+     * 
+     * @param volume The volume to move.
+     * @param newVirtualDatacenter The destination virtual datacenter.
+     * @return The reference to the volume in the new virtual datacenter.
+     */
+    @EnterpriseEdition
+    VolumeManagementDto moveVolume(VolumeManagementDto volume,
+        VirtualDatacenterDto newVirtualDatacenter);
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/CloudAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/CloudAsyncApi.java
new file mode 100644
index 0000000..ce59a8b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/CloudAsyncApi.java
@@ -0,0 +1,764 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+
+import org.jclouds.abiquo.binders.AppendToPath;
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.abiquo.binders.BindToXMLPayloadAndPath;
+import org.jclouds.abiquo.binders.cloud.BindHardDiskRefsToPayload;
+import org.jclouds.abiquo.binders.cloud.BindMoveVolumeToPath;
+import org.jclouds.abiquo.binders.cloud.BindNetworkConfigurationRefToPayload;
+import org.jclouds.abiquo.binders.cloud.BindNetworkRefToPayload;
+import org.jclouds.abiquo.binders.cloud.BindVirtualDatacenterRefToPayload;
+import org.jclouds.abiquo.binders.cloud.BindVolumeRefsToPayload;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.options.VirtualApplianceOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualDatacenterOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineTemplateOptions;
+import org.jclouds.abiquo.domain.cloud.options.VolumeOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.functions.ReturnTaskReferenceOrNull;
+import org.jclouds.abiquo.functions.cloud.ReturnMovedVolume;
+import org.jclouds.abiquo.functions.enterprise.ParseEnterpriseId;
+import org.jclouds.abiquo.functions.infrastructure.ParseDatacenterId;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.ParamParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualApplianceStateDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.cloud.VirtualDatacentersDto;
+import com.abiquo.server.core.cloud.VirtualMachineDto;
+import com.abiquo.server.core.cloud.VirtualMachineStateDto;
+import com.abiquo.server.core.cloud.VirtualMachineTaskDto;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpsDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.abiquo.server.core.infrastructure.network.VMNetworkConfigurationDto;
+import com.abiquo.server.core.infrastructure.network.VMNetworkConfigurationsDto;
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+import com.abiquo.server.core.infrastructure.storage.DisksManagementDto;
+import com.abiquo.server.core.infrastructure.storage.MovedVolumeDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.abiquo.server.core.infrastructure.storage.VolumesManagementDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Abiquo Cloud API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see CloudApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+@Path("/cloud")
+public interface CloudAsyncApi
+{
+    /*********************** Virtual Datacenter ***********************/
+
+    /**
+     * @see CloudApi#listVirtualDatacenters(VirtualDatacenterOptions)
+     */
+    @GET
+    @Path("/virtualdatacenters")
+    @Consumes(VirtualDatacentersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualDatacentersDto> listVirtualDatacenters(VirtualDatacenterOptions options);
+
+    /**
+     * @see CloudApi#getVirtualDatacenter(Integer)
+     */
+    @GET
+    @Path("/virtualdatacenters/{virtualdatacenter}")
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    @Consumes(VirtualDatacenterDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualDatacenterDto> getVirtualDatacenter(
+        @PathParam("virtualdatacenter") Integer virtualDatacenterId);
+
+    /**
+     * @see CloudApi#createVirtualDatacenter(VirtualDatacenterDto, Datacenter, Enterprise)
+     */
+    @POST
+    @Path("/virtualdatacenters")
+    @Consumes(VirtualDatacenterDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualDatacenterDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualDatacenterDto> createVirtualDatacenter(
+        @BinderParam(BindToXMLPayload.class) final VirtualDatacenterDto virtualDatacenter,
+        @QueryParam("datacenter") @ParamParser(ParseDatacenterId.class) final DatacenterDto datacenter,
+        @QueryParam("enterprise") @ParamParser(ParseEnterpriseId.class) final EnterpriseDto enterprise);
+
+    /**
+     * @see CloudApi#updateVirtualDatacenter(VirtualDatacenterDto)
+     */
+    @PUT
+    @Consumes(VirtualDatacenterDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualDatacenterDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualDatacenterDto> updateVirtualDatacenter(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#deleteVirtualDatacenter(VirtualDatacenterDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteVirtualDatacenter(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#listAvailableTemplates(VirtualDatacenterDto)
+     */
+    @GET
+    @Consumes(VirtualMachineTemplatesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineTemplatesDto> listAvailableTemplates(
+        @EndpointLink("templates") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#listAvailableTemplates(VirtualDatacenterDto, VirtualMachineTemplateOptions)
+     */
+    @GET
+    @Consumes(VirtualMachineTemplatesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineTemplatesDto> listAvailableTemplates(
+        @EndpointLink("templates") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        VirtualMachineTemplateOptions options);
+
+    /**
+     * @see CloudApi#listStorageTiers(VirtualDatacenterDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(TiersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<TiersDto> listStorageTiers(
+        @EndpointLink("tiers") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#getStorageTier(VirtualDatacenterDto, Integer)
+     */
+    @EnterpriseEdition
+    @GET
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    @Consumes(TierDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<TierDto> getStorageTier(
+        @EndpointLink("tiers") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(AppendToPath.class) Integer tierId);
+
+    /*********************** Public IP ***********************/
+
+    /**
+     * @see CloudApi#listAvailablePublicIps(VirtualDatacenterDto, IpOptions)
+     */
+    @GET
+    @Consumes(PublicIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PublicIpsDto> listAvailablePublicIps(
+        @EndpointLink("topurchase") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        IpOptions options);
+
+    /**
+     * @see CloudApi#listPurchasedPublicIps(VirtualDatacenterDto, IpOptions)
+     */
+    @GET
+    @Consumes(PublicIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PublicIpsDto> listPurchasedPublicIps(
+        @EndpointLink("purchased") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        IpOptions options);
+
+    /**
+     * @see CloudApi#purchasePublicIp(PublicIpDto)
+     */
+    @PUT
+    @Consumes(PublicIpDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PublicIpDto> purchasePublicIp(
+        @EndpointLink("purchase") @BinderParam(BindToPath.class) PublicIpDto publicIp);
+
+    /**
+     * @see CloudApi#releasePublicIp(PublicIpDto)
+     */
+    @PUT
+    @Consumes(PublicIpDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PublicIpDto> releasePublicIp(
+        @EndpointLink("release") @BinderParam(BindToPath.class) PublicIpDto publicIp);
+
+    /*********************** Private Network ***********************/
+
+    /**
+     * @see CloudApi#listPrivateNetworks(VirtualDatacenter)
+     */
+    @GET
+    @Consumes(VLANNetworksDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworksDto> listPrivateNetworks(
+        @EndpointLink("privatenetworks") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#getPrivateNetwork(VirtualDatacenterDto, Integer)
+     */
+    @GET
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    @Consumes(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworkDto> getPrivateNetwork(
+        @EndpointLink("privatenetworks") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(AppendToPath.class) Integer privateNetworkId);
+
+    /**
+     * @see CloudApi#createPrivateNetwork(VirtualDatacenterDto, VLANNetworkDto)
+     */
+    @POST
+    @Consumes(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @Produces(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworkDto> createPrivateNetwork(
+        @EndpointLink("privatenetworks") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(BindToXMLPayload.class) VLANNetworkDto privateNetwork);
+
+    /**
+     * @see CloudApi#updatePrivateNetwork(VLANNetworkDto)
+     */
+    @PUT
+    @Consumes(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @Produces(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworkDto> updatePrivateNetwork(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) VLANNetworkDto privateNetwork);
+
+    /**
+     * @see CloudApi#deletePrivateNetwork(VLANNetworkDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deletePrivateNetwork(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) VLANNetworkDto privateNetwork);
+
+    /**
+     * @see CloudApi#getDefaultNetwork(VirtualDatacenterDto)
+     */
+    @GET
+    @Consumes(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworkDto> getDefaultNetwork(
+        @EndpointLink("defaultnetwork") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#setDefaultNetwork(VirtualDatacenterDto, VLANNetworkDto)
+     */
+    @PUT
+    @Produces(LinksDto.BASE_MEDIA_TYPE)
+    ListenableFuture<Void> setDefaultNetwork(
+        @EndpointLink("defaultvlan") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(BindNetworkRefToPayload.class) VLANNetworkDto network);
+
+    /*********************** Private Network IPs ***********************/
+
+    /**
+     * @see CloudApi#listPrivateNetworkIps(VLANNetworkDto)
+     */
+    @GET
+    @Consumes(PrivateIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PrivateIpsDto> listPrivateNetworkIps(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network);
+
+    /**
+     * @see CloudApi#listPrivateNetworkIps(VLANNetworkDto, IpOptions)
+     */
+    @GET
+    @Consumes(PrivateIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PrivateIpsDto> listPrivateNetworkIps(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network,
+        IpOptions options);
+
+    /**
+     * @see CloudApi#getPrivateNetworkIp(VLANNetworkDto, Integer)
+     */
+    @GET
+    @Consumes(PrivateIpDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PrivateIpDto> getPrivateNetworkIp(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network,
+        @BinderParam(AppendToPath.class) Integer ipId);
+
+    /*********************** Virtual Appliance ***********************/
+
+    /**
+     * @see CloudApi#listVirtualAppliances(VirtualDatacenterDto)
+     */
+    @GET
+    @Consumes(VirtualAppliancesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualAppliancesDto> listVirtualAppliances(
+        @EndpointLink("virtualappliances") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#getVirtualAppliance(VirtualDatacenterDto, Integer)
+     */
+    @GET
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    @Consumes(VirtualApplianceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualApplianceDto> getVirtualAppliance(
+        @EndpointLink("virtualappliances") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(AppendToPath.class) Integer virtualApplianceId);
+
+    /**
+     * @see CloudApi#getVirtualApplianceState(VirtualApplianceDto)
+     */
+    @GET
+    @Consumes(VirtualApplianceStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualApplianceStateDto> getVirtualApplianceState(
+        @EndpointLink("state") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance);
+
+    /**
+     * @see CloudApi#createVirtualAppliance(VirtualDatacenterDto, VirtualApplianceDto)
+     */
+    @POST
+    @Consumes(VirtualApplianceDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualApplianceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualApplianceDto> createVirtualAppliance(
+        @EndpointLink("virtualappliances") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(BindToXMLPayload.class) VirtualApplianceDto virtualAppliance);
+
+    /**
+     * @see CloudApi#updateVirtualAppliance(VirtualApplianceDto)
+     */
+    @PUT
+    @Consumes(VirtualApplianceDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualApplianceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualApplianceDto> updateVirtualAppliance(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) VirtualApplianceDto virtualAppliance);
+
+    /**
+     * @see CloudApi#deleteVirtualAppliance(VirtualApplianceDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteVirtualAppliance(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance);
+
+    /**
+     * @see CloudApi#deleteVirtualAppliance(VirtualApplianceDto, VirtualApplianceOptions)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteVirtualAppliance(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance,
+        VirtualApplianceOptions options);
+
+    /**
+     * @see CloudApi#deployVirtualAppliance(VirtualApplianceDto, VirtualMachineTaskDto)
+     */
+    @POST
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineTaskDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<AcceptedRequestDto<String>> deployVirtualAppliance(
+        @EndpointLink("deploy") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance,
+        @BinderParam(BindToXMLPayload.class) VirtualMachineTaskDto task);
+
+    /**
+     * @see CloudApi#undeployVirtualAppliance(VirtualApplianceDto, VirtualMachineTaskDto)
+     */
+    @POST
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineTaskDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<AcceptedRequestDto<String>> undeployVirtualAppliance(
+        @EndpointLink("undeploy") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance,
+        @BinderParam(BindToXMLPayload.class) VirtualMachineTaskDto task);
+
+    /*********************** Virtual Machine ***********************/
+
+    /**
+     * @see CloudApi#listVirtualMachines(VirtualApplianceDto)
+     */
+    @GET
+    @Consumes(VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachinesWithNodeExtendedDto> listVirtualMachines(
+        @EndpointLink("virtualmachines") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance);
+
+    /**
+     * @see CloudApi#listVirtualMachines(VirtualApplianceDto, VirtualMachineOptions)
+     */
+    @GET
+    @Consumes(VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachinesWithNodeExtendedDto> listVirtualMachines(
+        @EndpointLink("virtualmachines") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance,
+        VirtualMachineOptions options);
+
+    /**
+     * @see CloudApi#getVirtualMachine(VirtualApplianceDto, Integer)
+     */
+    @GET
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    @Consumes(VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineWithNodeExtendedDto> getVirtualMachine(
+        @EndpointLink("virtualmachines") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance,
+        @BinderParam(AppendToPath.class) Integer virtualMachineId);
+
+    /**
+     * @see CloudApi#createVirtualMachine(VirtualApplianceDto, VirtualMachineWithNodeExtendedDto)
+     */
+    @POST
+    @Consumes(VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineWithNodeExtendedDto> createVirtualMachine(
+        @EndpointLink("virtualmachines") @BinderParam(BindToPath.class) VirtualApplianceDto virtualAppliance,
+        @BinderParam(BindToXMLPayload.class) VirtualMachineWithNodeExtendedDto virtualMachine);
+
+    /**
+     * @see CloudApi#deleteVirtualMachine(VirtualMachineDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteVirtualMachine(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /**
+     * @see CloudApi#updateVirtualMachine(VirtualMachineWithNodeExtendedDto)
+     */
+    @PUT
+    @ResponseParser(ReturnTaskReferenceOrNull.class)
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    ListenableFuture<AcceptedRequestDto<String>> updateVirtualMachine(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) VirtualMachineWithNodeExtendedDto virtualMachine);
+
+    /**
+     * @see CloudApi#updateVirtualMachine(VirtualMachineDto, VirtualMachineOptions)
+     */
+    @PUT
+    @ResponseParser(ReturnTaskReferenceOrNull.class)
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    ListenableFuture<AcceptedRequestDto<String>> updateVirtualMachine(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) VirtualMachineWithNodeExtendedDto virtualMachine,
+        VirtualMachineOptions options);
+
+    /**
+     * @see CloudApi#changeVirtualMachineState(VirtualMachineDto, VirtualMachineStateDto)
+     */
+    @PUT
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<AcceptedRequestDto<String>> changeVirtualMachineState(
+        @EndpointLink("state") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine,
+        @BinderParam(BindToXMLPayload.class) VirtualMachineStateDto state);
+
+    /**
+     * @see CloudApi#getVirtualMachineState(VirtualMachineDto)
+     */
+    @GET
+    @Consumes(VirtualMachineStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineStateDto> getVirtualMachineState(
+        @EndpointLink("state") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /**
+     * @see CloudApi#listNetworkConfigurations(VirtualMachineDto)
+     */
+    @GET
+    @Consumes(VMNetworkConfigurationsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VMNetworkConfigurationsDto> listNetworkConfigurations(
+        @EndpointLink("configurations") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /**
+     * @see CloudApi#setGatewayNetwork(VirtualMachineDto, VMNetworkConfigurationDto)
+     */
+    @PUT
+    @Produces(LinksDto.BASE_MEDIA_TYPE)
+    ListenableFuture<Void> setGatewayNetwork(
+        @EndpointLink("configurations") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine,
+        @BinderParam(BindNetworkConfigurationRefToPayload.class) VLANNetworkDto network);
+
+    /**
+     * @see CloudApi#rebootVirtualMachine(VirtualMachineDto)
+     */
+    @POST
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<AcceptedRequestDto<String>> rebootVirtualMachine(
+        @EndpointLink("reset") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /*********************** Virtual Machine Template ***********************/
+
+    /**
+     * @see CloudApi#getVirtualMachineTemplate(VirtualMachineTemplateDto)
+     */
+    @GET
+    @Consumes(VirtualMachineTemplateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineTemplateDto> getVirtualMachineTemplate(
+        @EndpointLink("virtualmachinetemplate") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /**
+     * @see CloudApi#listAttachedVolumes(VirtualMachineDto)
+     */
+    @GET
+    @Consumes(VolumesManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VolumesManagementDto> listAttachedVolumes(
+        @EndpointLink("volumes") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /**
+     * @see CloudApi#detachAllVolumes(VirtualMachineDto)
+     */
+    @DELETE
+    @ResponseParser(ReturnTaskReferenceOrNull.class)
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    ListenableFuture<AcceptedRequestDto<String>> detachAllVolumes(
+        @EndpointLink("volumes") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /**
+     * @see CloudApi#replaceVolumes(VirtualMachineDto, VirtualMachineOptions,
+     *      VolumeManagementDto...)
+     */
+    @PUT
+    @ResponseParser(ReturnTaskReferenceOrNull.class)
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(LinksDto.BASE_MEDIA_TYPE)
+    ListenableFuture<AcceptedRequestDto<String>> replaceVolumes(
+        @EndpointLink("volumes") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine,
+        VirtualMachineOptions options,
+        @BinderParam(BindVolumeRefsToPayload.class) VolumeManagementDto... volumes);
+
+    /**
+     * @see CloudApi#listAttachedHardDisks(VirtualMachineDto)
+     */
+    @GET
+    @Consumes(DisksManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DisksManagementDto> listAttachedHardDisks(
+        @EndpointLink("disks") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /**
+     * @see CloudApi#detachAllHardDisks(VirtualMachineDto)
+     */
+    @DELETE
+    @ResponseParser(ReturnTaskReferenceOrNull.class)
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    ListenableFuture<AcceptedRequestDto<String>> detachAllHardDisks(
+        @EndpointLink("disks") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
+
+    /**
+     * @see CloudApi#replaceHardDisks(VirtualMachineDto, DiskManagementDto...)
+     */
+    @PUT
+    @ResponseParser(ReturnTaskReferenceOrNull.class)
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(LinksDto.BASE_MEDIA_TYPE)
+    ListenableFuture<AcceptedRequestDto<String>> replaceHardDisks(
+        @EndpointLink("disks") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine,
+        @BinderParam(BindHardDiskRefsToPayload.class) DiskManagementDto... hardDisks);
+
+    /**
+     * @see CloudApi#deployVirtualMachine(VirtualMachineDto, VirtualMachineTaskDto)
+     */
+    @POST
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineTaskDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<AcceptedRequestDto<String>> deployVirtualMachine(
+        @EndpointLink("deploy") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine,
+        @BinderParam(BindToXMLPayload.class) VirtualMachineTaskDto task);
+
+    /**
+     * @see CloudApi#undeployVirtualMachine(VirtualMachineDto, VirtualMachineTaskDto)
+     */
+    @POST
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineTaskDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<AcceptedRequestDto<String>> undeployVirtualMachine(
+        @EndpointLink("undeploy") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine,
+        @BinderParam(BindToXMLPayload.class) VirtualMachineTaskDto task);
+
+    /*********************** Hard disks ***********************/
+
+    /**
+     * @see CloudApi#listHardDisks(VirtualDatacenterDto)
+     */
+    @GET
+    @Consumes(DisksManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DisksManagementDto> listHardDisks(
+        @EndpointLink("disks") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#getHardDisk(VirtualDatacenterDto, Integer)
+     */
+    @GET
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    @Consumes(DiskManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DiskManagementDto> getHardDisk(
+        @EndpointLink("disks") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(AppendToPath.class) Integer diskId);
+
+    /**
+     * @see CloudApi#createHardDisk(VirtualDatacenterDto, DiskManagementDto)
+     */
+    @POST
+    @Consumes(DiskManagementDto.BASE_MEDIA_TYPE)
+    @Produces(DiskManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DiskManagementDto> createHardDisk(
+        @EndpointLink("disks") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(BindToXMLPayload.class) DiskManagementDto hardDisk);
+
+    /**
+     * @see CloudApi#deleteHardDisk(DiskManagementDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteHardDisk(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) DiskManagementDto hardDisk);
+
+    /*********************** Volumes ***********************/
+
+    /**
+     * @see CloudApi#listVolumes(VirtualDatacenterDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(VolumesManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VolumesManagementDto> listVolumes(
+        @EndpointLink("volumes") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter);
+
+    /**
+     * @see CloudApi#listVolumes(VirtualDatacenterDto, VolumeOptions)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(VolumesManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VolumesManagementDto> listVolumes(
+        @EndpointLink("volumes") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        VolumeOptions options);
+
+    /**
+     * @see CloudApi#getVolume(VirtualDatacenterDto, Integer)
+     */
+    @EnterpriseEdition
+    @GET
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    @Consumes(VolumeManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VolumeManagementDto> getVolume(
+        @EndpointLink("volumes") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(AppendToPath.class) Integer volumeId);
+
+    /**
+     * @see CloudApi#createVolume(VirtualDatacenterDto, VolumeManagementDto)
+     */
+    @EnterpriseEdition
+    @POST
+    @Consumes(VolumeManagementDto.BASE_MEDIA_TYPE)
+    @Produces(VolumeManagementDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VolumeManagementDto> createVolume(
+        @EndpointLink("volumes") @BinderParam(BindToPath.class) VirtualDatacenterDto virtualDatacenter,
+        @BinderParam(BindToXMLPayload.class) VolumeManagementDto volume);
+
+    /**
+     * @see CloudApi#updateVolume(VolumeManagementDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    @ResponseParser(ReturnTaskReferenceOrNull.class)
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VolumeManagementDto.BASE_MEDIA_TYPE)
+    ListenableFuture<AcceptedRequestDto<String>> updateVolume(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) VolumeManagementDto volume);
+
+    /**
+     * @see CloudApi#updateVolume(VolumeManagementDto)
+     */
+    @EnterpriseEdition
+    @DELETE
+    ListenableFuture<Void> deleteVolume(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) VolumeManagementDto volume);
+
+    /**
+     * @see CloudApi#moveVolume(VolumeManagementDto, VirtualDatacenterDto)
+     */
+    @EnterpriseEdition
+    @POST
+    @ExceptionParser(ReturnMovedVolume.class)
+    @Consumes(MovedVolumeDto.BASE_MEDIA_TYPE)
+    @Produces(LinksDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VolumeManagementDto> moveVolume(
+        @BinderParam(BindMoveVolumeToPath.class) VolumeManagementDto volume,
+        @BinderParam(BindVirtualDatacenterRefToPayload.class) VirtualDatacenterDto newVirtualDatacenter);
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/ConfigApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/ConfigApi.java
new file mode 100644
index 0000000..3e819ae
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/ConfigApi.java
@@ -0,0 +1,167 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.config.options.LicenseOptions;
+import org.jclouds.abiquo.domain.config.options.PropertyOptions;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.server.core.appslibrary.CategoriesDto;
+import com.abiquo.server.core.appslibrary.CategoryDto;
+import com.abiquo.server.core.config.LicenseDto;
+import com.abiquo.server.core.config.LicensesDto;
+import com.abiquo.server.core.config.SystemPropertiesDto;
+import com.abiquo.server.core.config.SystemPropertyDto;
+import com.abiquo.server.core.enterprise.PrivilegeDto;
+import com.abiquo.server.core.enterprise.PrivilegesDto;
+
+/**
+ * Provides synchronous access to Abiquo Admin API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see ConfigAsyncApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface ConfigApi
+{
+    /*********************** License ***********************/
+
+    /**
+     * List all licenses.
+     * 
+     * @return The list of licenses.
+     */
+    @EnterpriseEdition
+    LicensesDto listLicenses();
+
+    /**
+     * List all active/inactive licenses.
+     * 
+     * @param options Optional query params.
+     * @return The list of licenses.
+     */
+    @EnterpriseEdition
+    LicensesDto listLicenses(LicenseOptions options);
+
+    /**
+     * Add a new license.
+     * 
+     * @param license The license to add.
+     * @return The added license.
+     */
+    @EnterpriseEdition
+    LicenseDto addLicense(LicenseDto license);
+
+    /**
+     * Removes an existing license.
+     * 
+     * @param license The license to delete.
+     */
+    @EnterpriseEdition
+    void removeLicense(LicenseDto license);
+
+    /*********************** Privilege ***********************/
+
+    /**
+     * List all privileges in the system.
+     * 
+     * @return The list of privileges.
+     */
+    PrivilegesDto listPrivileges();
+
+    /**
+     * Get the given privilege.
+     * 
+     * @param privilegeId The id of the privilege.
+     * @return The privilege or <code>null</code> if it does not exist.
+     */
+    PrivilegeDto getPrivilege(Integer privilegeId);
+
+    /*********************** System Properties ***********************/
+
+    /**
+     * List all system properties.
+     * 
+     * @return The list of properties.
+     */
+    SystemPropertiesDto listSystemProperties();
+
+    /**
+     * List properties with options.
+     * 
+     * @param options Optional query params.
+     * @return The list of system properties.
+     */
+    SystemPropertiesDto listSystemProperties(PropertyOptions options);
+
+    /**
+     * Updates a system property.
+     * 
+     * @param property The new attributes for the system property.
+     * @return The updated system property.
+     */
+    SystemPropertyDto updateSystemProperty(SystemPropertyDto property);
+
+    /*********************** Category ***********************/
+
+    /**
+     * List all categories.
+     * 
+     * @return The list of categories.
+     */
+    CategoriesDto listCategories();
+
+    /**
+     * Get the given category.
+     * 
+     * @param categoryId The id of the category.
+     * @return The category or <code>null</code> if it does not exist.
+     */
+    CategoryDto getCategory(Integer categoryId);
+
+    /**
+     * Create a new category.
+     * 
+     * @param icon The category to be created.
+     * @return The created category.
+     */
+    CategoryDto createCategory(CategoryDto category);
+
+    /**
+     * Updates an existing category.
+     * 
+     * @param category The new attributes for the category.
+     * @return The updated category.
+     */
+    CategoryDto updateCategory(CategoryDto category);
+
+    /**
+     * Deletes an existing category.
+     * 
+     * @param icon The category to delete.
+     */
+    void deleteCategory(CategoryDto category);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/ConfigAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/ConfigAsyncApi.java
new file mode 100644
index 0000000..d84ad5d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/ConfigAsyncApi.java
@@ -0,0 +1,211 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.abiquo.binders.BindToXMLPayloadAndPath;
+import org.jclouds.abiquo.domain.config.options.LicenseOptions;
+import org.jclouds.abiquo.domain.config.options.PropertyOptions;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.abiquo.server.core.appslibrary.CategoriesDto;
+import com.abiquo.server.core.appslibrary.CategoryDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.config.LicenseDto;
+import com.abiquo.server.core.config.LicensesDto;
+import com.abiquo.server.core.config.SystemPropertiesDto;
+import com.abiquo.server.core.config.SystemPropertyDto;
+import com.abiquo.server.core.enterprise.PrivilegeDto;
+import com.abiquo.server.core.enterprise.PrivilegesDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Abiquo Config API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see AdminApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+@Path("/config")
+public interface ConfigAsyncApi
+{
+    /*********************** License ***********************/
+
+    /**
+     * @see ConfigApi#listLicenses()
+     */
+
+    @EnterpriseEdition
+    @GET
+    @Path("/licenses")
+    @Consumes(LicensesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<LicensesDto> listLicenses();
+
+    /**
+     * @see ConfigApi#listLicenses(LicenseOptions)
+     */
+    @EnterpriseEdition
+    @GET
+    @Path("/licenses")
+    @Consumes(LicensesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<LicensesDto> listLicenses(LicenseOptions options);
+
+    /**
+     * @see ConfigApi#addLicense(LicenseDto)
+     */
+    @EnterpriseEdition
+    @POST
+    @Produces(LicenseDto.BASE_MEDIA_TYPE)
+    @Consumes(LicenseDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @Path("/licenses")
+    ListenableFuture<LicenseDto> addLicense(@BinderParam(BindToXMLPayload.class) LicenseDto license);
+
+    /**
+     * @see ConfigApi#removeLicense(LicenseDto)
+     */
+    @DELETE
+    @EnterpriseEdition
+    ListenableFuture<Void> removeLicense(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) LicenseDto license);
+
+    /*********************** Privilege ***********************/
+
+    /**
+     * @see ConfigApi#listPrivileges()
+     */
+    @GET
+    @Path("/privileges")
+    @Consumes(PrivilegesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PrivilegesDto> listPrivileges();
+
+    /**
+     * @see ConfigApi#getPrivilege(Integer)
+     */
+    @GET
+    @Path("/privileges/{privilege}")
+    @Consumes(PrivilegeDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<PrivilegeDto> getPrivilege(@PathParam("privilege") Integer privilegeId);
+
+    /*********************** System Properties ***********************/
+
+    /**
+     * @see ConfigApi#listSystemProperties()
+     */
+    @GET
+    @Path("/properties")
+    @Consumes(SystemPropertiesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<SystemPropertiesDto> listSystemProperties();
+
+    /**
+     * @see ConfigApi#listSystemProperties(PropertyOptions)
+     */
+    @GET
+    @Path("/properties")
+    @Consumes(SystemPropertiesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<SystemPropertiesDto> listSystemProperties(PropertyOptions options);
+
+    /**
+     * @see ConfigApi#updateSystemProperty(VirtualDatacenterDto)
+     */
+    @PUT
+    @Produces(SystemPropertyDto.BASE_MEDIA_TYPE)
+    @Consumes(SystemPropertyDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<SystemPropertyDto> updateSystemProperty(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) SystemPropertyDto property);
+
+    /*********************** Category ***********************/
+
+    /**
+     * @see ConfigApi#listCategories()
+     */
+    @GET
+    @Path("/categories")
+    @Consumes(CategoriesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<CategoriesDto> listCategories();
+
+    /**
+     * @see ConfigApi#getCategory(Integer)
+     */
+    @GET
+    @Path("/categories/{category}")
+    @Consumes(CategoryDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<CategoryDto> getCategory(@PathParam("category") Integer categoryId);
+
+    /**
+     * @see ConfigApi#createCategory(CategoryDto)
+     */
+    @POST
+    @Path("/categories")
+    @Produces(CategoryDto.BASE_MEDIA_TYPE)
+    @Consumes(CategoryDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<CategoryDto> createCategory(
+        @BinderParam(BindToXMLPayload.class) CategoryDto category);
+
+    /**
+     * @see ConfigApi#updateCategory(CategoryDto)
+     */
+    @PUT
+    @Produces(CategoryDto.BASE_MEDIA_TYPE)
+    @Consumes(CategoryDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<CategoryDto> updateCategory(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) CategoryDto category);
+
+    /**
+     * @see ConfigApi#deleteCategory(CategoryDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteCategory(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) CategoryDto category);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EnterpriseApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EnterpriseApi.java
new file mode 100644
index 0000000..db01154
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EnterpriseApi.java
@@ -0,0 +1,359 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.enterprise.options.EnterpriseOptions;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.am.model.TemplatesStateDto;
+import com.abiquo.server.core.appslibrary.DatacenterRepositoryDto;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListDto;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListsDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.abiquo.server.core.cloud.VirtualDatacentersDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.DatacenterLimitsDto;
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.EnterprisePropertiesDto;
+import com.abiquo.server.core.enterprise.EnterprisesDto;
+import com.abiquo.server.core.enterprise.UserDto;
+import com.abiquo.server.core.enterprise.UsersDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+
+/**
+ * Provides synchronous access to Abiquo Enterprise API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see EnterpriseAsyncApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface EnterpriseApi
+{
+
+    /*********************** Enterprise ********************** */
+
+    /**
+     * List all enterprises.
+     * 
+     * @return The list of Enterprises.
+     */
+    EnterprisesDto listEnterprises();
+
+    /**
+     * List enterprises with options.
+     * 
+     * @param options Filtering options.
+     * @return The list of Enterprises.
+     */
+    EnterprisesDto listEnterprises(EnterpriseOptions options);
+
+    /**
+     * List filtered enterprises by datacenter.
+     * 
+     * @param datacenter The given datacenter.
+     * @param options Filtering options.
+     * @return The list of Enterprises.
+     */
+    EnterprisesDto listEnterprises(DatacenterDto datacenter, EnterpriseOptions options);
+
+    /**
+     * Create a new enterprise.
+     * 
+     * @param enterprise The enterprise to be created.
+     * @return The created enterprise.
+     */
+    EnterpriseDto createEnterprise(EnterpriseDto enterprise);
+
+    /**
+     * Get the given enterprise.
+     * 
+     * @param enterpriseId The id of the enterprise.
+     * @return The enterprise or <code>null</code> if it does not exist.
+     */
+    EnterpriseDto getEnterprise(Integer enterpriseId);
+
+    /**
+     * Updates an existing enterprise.
+     * 
+     * @param enterprise The new attributes for the enterprise.
+     * @return The updated enterprise.
+     */
+    EnterpriseDto updateEnterprise(EnterpriseDto enterprise);
+
+    /**
+     * Deletes an existing enterprise.
+     * 
+     * @param enterprise The enterprise to delete.
+     */
+    void deleteEnterprise(EnterpriseDto enterprise);
+
+    /**
+     * List the allowed datacenters to the given enterprise.
+     * 
+     * @param enterpriseId The id of the enterprise.
+     * @return The allowed datacenters to the given enterprise.
+     */
+    DatacentersDto listAllowedDatacenters(Integer enterpriseId);
+
+    /**
+     * List all virtual datacenters of an enterprise.
+     * 
+     * @param enterprise The given enterprise.
+     * @return The list of Datacenters.
+     */
+    VirtualDatacentersDto listVirtualDatacenters(EnterpriseDto enterprise);
+
+    /*********************** Enterprise Properties ***********************/
+
+    /**
+     * Get defined properties of the given enterprise.
+     * 
+     * @param enterpriseId The enterprise id.
+     * @return Set of enterprise properties.
+     */
+    @EnterpriseEdition
+    EnterprisePropertiesDto getEnterpriseProperties(EnterpriseDto enterprise);
+
+    /**
+     * Updates the given enterprise properties set.
+     * 
+     * @param properties The properties set.
+     * @return The updated properties.
+     */
+    @EnterpriseEdition
+    EnterprisePropertiesDto updateEnterpriseProperties(EnterprisePropertiesDto properties);
+
+    /*********************** Enterprise Limits ***********************/
+
+    /**
+     * Allows the given enterprise to use the given datacenter with the given limits.
+     * 
+     * @param enterprise The enterprise.
+     * @param datacenter The datacenter to allow to the given enterprise.
+     * @param limits The usage limits for the enterprise in the given datacenter.
+     * @return The usage limits for the enterprise in the given datacenter.
+     */
+    DatacenterLimitsDto createLimits(final EnterpriseDto enterprise,
+        final DatacenterDto datacenter, final DatacenterLimitsDto limits);
+
+    /**
+     * Retreives the limits for the given enterprise and datacenter.
+     * 
+     * @param enterprise The enterprise.
+     * @param datacenter The datacenter.
+     * @return The usage limits for the enterprise in the given datacenter.
+     */
+    DatacentersLimitsDto getLimits(EnterpriseDto enterprise, DatacenterDto datacenter);
+
+    /**
+     * Retreives limits for the given enterprise and any datacenter.
+     * 
+     * @param enterprise The enterprise.
+     * @return The usage limits for the enterprise on any datacenter.
+     */
+    DatacentersLimitsDto listLimits(EnterpriseDto enterprise);
+
+    /**
+     * Updates an existing enterprise-datacenter limits.
+     * 
+     * @param limits The new set of limits.
+     * @return The updated limits.
+     */
+    DatacenterLimitsDto updateLimits(DatacenterLimitsDto limits);
+
+    /**
+     * Deletes existing limits for a pair enterprise-datacenter.
+     * 
+     * @param limits The limits to delete.
+     */
+    void deleteLimits(DatacenterLimitsDto limits);
+
+    /*********************** User ********************** */
+
+    /**
+     * Retreives users of the given enterprise.
+     * 
+     * @param enterprise The enterprise.
+     * @return The users of the enterprise.
+     */
+    UsersDto listUsers(final EnterpriseDto enterprise);
+
+    /**
+     * Create a new user in the given enterprise.
+     * 
+     * @param enterprise The enterprise.
+     * @param user The user to be created.
+     * @return The created user.
+     */
+    UserDto createUser(EnterpriseDto enterprise, UserDto user);
+
+    /**
+     * Get the given user from the given enterprise.
+     * 
+     * @param enterprise The enterprise.
+     * @param userId The id of the user.
+     * @return The user or <code>null</code> if it does not exist.
+     */
+    UserDto getUser(final EnterpriseDto enterprise, final Integer idUser);
+
+    /**
+     * Updates an existing user.
+     * 
+     * @param enterprise The new attributes for the user.
+     * @return The updated user.
+     */
+    UserDto updateUser(UserDto user);
+
+    /**
+     * Deletes existing user.
+     * 
+     * @param user The user to delete.
+     */
+    void deleteUser(UserDto user);
+
+    /**
+     * Retrieves list of virtual machines by user.
+     * 
+     * @param user The user.
+     * @return The list of virtual machines of the user.
+     */
+    VirtualMachinesWithNodeExtendedDto listVirtualMachines(final UserDto user);
+
+    /*********************** Datacenter Repository ***********************/
+
+    /**
+     * Get the given datacenter repository from the given enterprise.
+     * 
+     * @param enterprise The enterprise.
+     * @param datacenterRepositoryId The id of the datacenter repository.
+     * @return The datacenter repository or <code>null</code> if it does not exist.
+     */
+    DatacenterRepositoryDto getDatacenterRepository(final EnterpriseDto enterprise,
+        final Integer datacenterRepositoryId);
+
+    /**
+     * Refreshes database with virtual machine templates existing in the repository filesystem.
+     * 
+     * @param enterpriseId Id of the enterprise which information will be refreshed.
+     * @param datacenterRepositoryId Id of the datacenter repository contaning the templates.
+     */
+    @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+    void refreshTemplateRepository(Integer enterpriseId, Integer datacenterRepositoryId);
+
+    /*********************** Network ***********************/
+
+    /**
+     * List external networks of the enterprise
+     * 
+     * @param enterprise The enterprise.
+     * @return The list of external networks created and assigned.
+     */
+    @EnterpriseEdition
+    VLANNetworksDto listExternalNetworks(EnterpriseDto enterprise);
+
+    /*********************** Cloud ***********************/
+
+    /**
+     * Retrieves list of virtual appliances by the given enterprise.
+     * 
+     * @param enterprise The enterprise.
+     * @return The list of virtual appliances of the enterprise.
+     */
+    VirtualAppliancesDto listVirtualAppliances(EnterpriseDto enterprise);
+
+    /**
+     * List virtual machines for the enterprise
+     * 
+     * @param enterprise The enterprise.
+     * @return The list of virtual machines by the enterprise.
+     */
+    VirtualMachinesWithNodeExtendedDto listVirtualMachines(EnterpriseDto enterprise);
+
+    /**
+     * List reserved machines for the enterprise
+     * 
+     * @param enterprise The enterprise.
+     * @return The list of reserverd machines by the enterprise.
+     */
+    MachinesDto listReservedMachines(EnterpriseDto enterprise);
+
+    /**
+     * List all template definitions in apps library.
+     * 
+     * @param enterprise The enterprise.
+     * @return The list of template definitions by the enterprise.
+     */
+    TemplateDefinitionListsDto listTemplateDefinitionLists(EnterpriseDto enterprise);
+
+    /**
+     * Create a new template definition list in apps library in the given enterprise.
+     * 
+     * @param enterprise The enterprise.
+     * @param template The template to be created.
+     * @return The created template.
+     */
+    TemplateDefinitionListDto createTemplateDefinitionList(EnterpriseDto enterprise,
+        TemplateDefinitionListDto templateList);
+
+    /**
+     * Update an existing template definition list in apps library.
+     * 
+     * @param template The template to be update.
+     * @return The updated template.
+     */
+    TemplateDefinitionListDto updateTemplateDefinitionList(TemplateDefinitionListDto templateList);
+
+    /**
+     * Deletes existing user.
+     * 
+     * @param user The user to delete.
+     */
+    void deleteTemplateDefinitionList(TemplateDefinitionListDto templateList);
+
+    /**
+     * Get the given template definition list from the given enterprise.
+     * 
+     * @param enterprise The enterprise.
+     * @param templateListId The id of the template definition list.
+     * @return The list or <code>null</code> if it does not exist.
+     */
+    TemplateDefinitionListDto getTemplateDefinitionList(final EnterpriseDto enterprise,
+        final Integer templateListId);
+
+    /**
+     * Get the list of status of a template definition list in a datacenter.
+     * 
+     * @param templateList The template definition list.
+     * @param datacenter The given datacenter.
+     * @return The list of states.
+     */
+    TemplatesStateDto listTemplateListStatus(TemplateDefinitionListDto templateList,
+        DatacenterDto datacenter);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EnterpriseAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EnterpriseAsyncApi.java
new file mode 100644
index 0000000..3838fbc
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EnterpriseAsyncApi.java
@@ -0,0 +1,425 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+
+import org.jclouds.abiquo.binders.AppendToPath;
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.abiquo.binders.BindToXMLPayloadAndPath;
+import org.jclouds.abiquo.domain.enterprise.options.EnterpriseOptions;
+import org.jclouds.abiquo.functions.infrastructure.ParseDatacenterId;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.ParamParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.abiquo.am.model.TemplatesStateDto;
+import com.abiquo.server.core.appslibrary.DatacenterRepositoryDto;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListDto;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListsDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.abiquo.server.core.cloud.VirtualDatacentersDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.DatacenterLimitsDto;
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.EnterprisePropertiesDto;
+import com.abiquo.server.core.enterprise.EnterprisesDto;
+import com.abiquo.server.core.enterprise.UserDto;
+import com.abiquo.server.core.enterprise.UsersDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Abiquo Enterprise API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see EnterpriseApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+@Path("/admin")
+public interface EnterpriseAsyncApi
+{
+    /*********************** Enterprise ***********************/
+
+    /**
+     * @see EnterpriseApi#listEnterprises()
+     */
+    @GET
+    @Path("/enterprises")
+    @Consumes(EnterprisesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EnterprisesDto> listEnterprises();
+
+    /**
+     * @see EnterpriseApi#listEnterprises(EnterpriseOptions)
+     */
+    @GET
+    @Path("/enterprises")
+    @Consumes(EnterprisesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EnterprisesDto> listEnterprises(EnterpriseOptions options);
+
+    /**
+     * @see EnterpriseApi#listEnterprises(DatacenterDto, EnterpriseOptions)
+     */
+    @GET
+    @Consumes(EnterprisesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EnterprisesDto> listEnterprises(
+        @EndpointLink("enterprises") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        EnterpriseOptions options);
+
+    /**
+     * @see EnterpriseApi#createEnterprise(EnterpriseDto)
+     */
+    @POST
+    @Path("/enterprises")
+    @Produces(EnterpriseDto.BASE_MEDIA_TYPE)
+    @Consumes(EnterpriseDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EnterpriseDto> createEnterprise(
+        @BinderParam(BindToXMLPayload.class) EnterpriseDto enterprise);
+
+    /**
+     * @see EnterpriseApi#getEnterprise(Integer)
+     */
+    @GET
+    @Path("/enterprises/{enterprise}")
+    @Consumes(EnterpriseDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<EnterpriseDto> getEnterprise(@PathParam("enterprise") Integer enterpriseId);
+
+    /**
+     * @see EnterpriseApi#updateEnterprise(EnterpriseDto)
+     */
+    @PUT
+    @Produces(EnterpriseDto.BASE_MEDIA_TYPE)
+    @Consumes(EnterpriseDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EnterpriseDto> updateEnterprise(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) EnterpriseDto enterprise);
+
+    /**
+     * @see EnterpriseApi#deleteEnterprise(EnterpriseDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteEnterprise(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /**
+     * @see EnterpriseApi#listAllowedDatacenters(Integer)
+     */
+    @GET
+    @Path("/datacenters")
+    @Consumes(DatacentersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DatacentersDto> listAllowedDatacenters(
+        @QueryParam("idEnterprise") Integer enterpriseId);
+
+    /**
+     * @see EnterpriseApi#listVirtualDatacenters(EnterpriseDto)
+     */
+    @GET
+    @Consumes(VirtualDatacentersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualDatacentersDto> listVirtualDatacenters(
+        @EndpointLink("cloud/virtualdatacenters") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /*********************** Enterprise Properties ***********************/
+
+    /**
+     * @see EnterpriseApi#getEnterpriseProperties(EnterpriseDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(EnterprisePropertiesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EnterprisePropertiesDto> getEnterpriseProperties(
+        @EndpointLink("properties") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /**
+     * @see EnterpriseApi#updateEnterpriseProperties(EnterprisePropertiesDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    @Produces(EnterprisePropertiesDto.BASE_MEDIA_TYPE)
+    @Consumes(EnterprisePropertiesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EnterprisePropertiesDto> updateEnterpriseProperties(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) EnterprisePropertiesDto properties);
+
+    /*********************** Enterprise Limits ***********************/
+
+    /**
+     * @see EnterpriseApi#createLimits(EnterpriseDto, DatacenterDto, DatacenterLimitsDto)
+     */
+    @POST
+    @Produces(DatacenterLimitsDto.BASE_MEDIA_TYPE)
+    @Consumes(DatacenterLimitsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DatacenterLimitsDto> createLimits(
+        @EndpointLink("limits") @BinderParam(BindToPath.class) final EnterpriseDto enterprise,
+        @QueryParam("datacenter") @ParamParser(ParseDatacenterId.class) final DatacenterDto datacenter,
+        @BinderParam(BindToXMLPayload.class) DatacenterLimitsDto limits);
+
+    /**
+     * @see EnterpriseApi#getLimits(EnterpriseDto, DatacenterDto)
+     */
+    @GET
+    @Consumes(DatacentersLimitsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<DatacentersLimitsDto> getLimits(
+        @EndpointLink("limits") @BinderParam(BindToPath.class) final EnterpriseDto enterprise,
+        @QueryParam("datacenter") @ParamParser(ParseDatacenterId.class) final DatacenterDto datacenter);
+
+    /**
+     * @see EnterpriseApi#updateLimits(DatacenterLimitsDto)
+     */
+    @PUT
+    @Produces(DatacenterLimitsDto.BASE_MEDIA_TYPE)
+    @Consumes(DatacenterLimitsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DatacenterLimitsDto> updateLimits(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) DatacenterLimitsDto limits);
+
+    /**
+     * @see EnterpriseApi#deleteLimits(DatacenterLimitsDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteLimits(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) DatacenterLimitsDto limits);
+
+    /**
+     * @see EnterpriseApi#listLimits(EnterpriseDto)
+     */
+    @GET
+    @Consumes(DatacentersLimitsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DatacentersLimitsDto> listLimits(
+        @EndpointLink("limits") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /*********************** User ***********************/
+
+    /**
+     * @see EnterpriseApi#listUsers(EnterpriseDto)
+     */
+    @GET
+    @Consumes(UsersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UsersDto> listUsers(
+        @EndpointLink("users") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /**
+     * @see EnterpriseApi#getUser(EnterpriseDto, Integer)
+     */
+    @GET
+    @Consumes(UserDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<UserDto> getUser(
+        @EndpointLink("users") @BinderParam(BindToPath.class) EnterpriseDto enterprise,
+        @BinderParam(AppendToPath.class) Integer userId);
+
+    /**
+     * @see EnterpriseApi#createUser(EnterpriseDto)
+     */
+    @POST
+    @Produces(UserDto.BASE_MEDIA_TYPE)
+    @Consumes(UserDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UserDto> createUser(
+        @EndpointLink("users") @BinderParam(BindToPath.class) EnterpriseDto enterprise,
+        @BinderParam(BindToXMLPayload.class) UserDto user);
+
+    /**
+     * @see EnterpriseApi#updateUser(UserDto)
+     */
+    @PUT
+    @Produces(UserDto.BASE_MEDIA_TYPE)
+    @Consumes(UserDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UserDto> updateUser(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) UserDto user);
+
+    /**
+     * @see EnterpriseApi#deleteUser(UserDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteUser(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) UserDto user);
+
+    /**
+     * @see EnterpriseApi#listVirtualMachines(UserDto)
+     */
+    @GET
+    @Consumes(VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachinesWithNodeExtendedDto> listVirtualMachines(
+        @EndpointLink("virtualmachines") @BinderParam(BindToPath.class) final UserDto user);
+
+    /*********************** Datacenter Repository ***********************/
+
+    /**
+     * @see EnterpriseApi#getDatacenterRepository(EnterpriseDto, Integer)
+     */
+    @GET
+    @Consumes(DatacenterRepositoryDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<UserDto> getDatacenterRepository(
+        @EndpointLink("datacenterrepositories") @BinderParam(BindToPath.class) EnterpriseDto enterprise,
+        @BinderParam(AppendToPath.class) Integer datacenterRepositoryId);
+
+    /**
+     * @see EnterpriseApi#refreshTemplateRepository(Integer, Integer)
+     */
+    @PUT
+    @Path("/enterprises/{enterprise}/datacenterrepositories/{datacenterrepository}/actions/refresh")
+    ListenableFuture<Void> refreshTemplateRepository(@PathParam("enterprise") Integer enterpriseId,
+        @PathParam("datacenterrepository") Integer datacenterRepositoryId);
+
+    /*********************** External Network ***********************/
+
+    /**
+     * @see EnterpriseApi#listExternalNetworks(EnterpriseDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(VLANNetworksDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworksDto> listExternalNetworks(
+        @EndpointLink("externalnetworks") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /*********************** Cloud ***********************/
+
+    /**
+     * @see EnterpriseApi#listVirtualAppliances(EnterpriseDto)
+     */
+    @GET
+    @Consumes(VirtualAppliancesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualAppliancesDto> listVirtualAppliances(
+        @EndpointLink("virtualappliances") @BinderParam(BindToPath.class) final EnterpriseDto enterprise);
+
+    /**
+     * @see EnterpriseApi#listVirtualMachines(EnterpriseDto)
+     */
+    @GET
+    @Consumes(VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachinesWithNodeExtendedDto> listVirtualMachines(
+        @EndpointLink("virtualmachines") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /*********************** Machine ***********************/
+
+    /**
+     * @see EnterpriseApi#listVirtualMachines(EnterpriseDto)
+     */
+    @GET
+    @Consumes(MachinesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<MachinesDto> listReservedMachines(
+        @EndpointLink("reservedmachines") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /*********************** Template definition list ***********************/
+
+    /**
+     * @see EnterpriseApi#listTemplateDefinitionLists(EnterpriseDto)
+     */
+    @GET
+    @Consumes(TemplateDefinitionListsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<TemplateDefinitionListsDto> listTemplateDefinitionLists(
+        @EndpointLink("appslib/templateDefinitionLists") @BinderParam(BindToPath.class) EnterpriseDto enterprise);
+
+    /**
+     * @see EnterpriseApi#createTemplateDefinitionList(EnterpriseDto, TemplateDefinitionListDto)
+     */
+    @POST
+    @Produces(TemplateDefinitionListDto.BASE_MEDIA_TYPE)
+    @Consumes(TemplateDefinitionListDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<TemplateDefinitionListDto> createTemplateDefinitionList(
+        @EndpointLink("appslib/templateDefinitionLists") @BinderParam(BindToPath.class) EnterpriseDto enterprise,
+        @BinderParam(BindToXMLPayload.class) TemplateDefinitionListDto templateList);
+
+    /**
+     * @see EnterpriseApi#updateTemplateDefinitionList(TemplateDefinitionListDto)
+     */
+    @PUT
+    @Produces(TemplateDefinitionListDto.BASE_MEDIA_TYPE)
+    @Consumes(TemplateDefinitionListDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<TemplateDefinitionListDto> updateTemplateDefinitionList(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) TemplateDefinitionListDto templateList);
+
+    /**
+     * @see EnterpriseApi#deleteTemplateDefinitionList(EnterpriseDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteTemplateDefinitionList(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) TemplateDefinitionListDto templateList);
+
+    /**
+     * @see EnterpriseApi#getTemplateDefinitionList(EnterpriseDto, Integer)
+     */
+    @GET
+    @Consumes(TemplateDefinitionListDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<TemplateDefinitionListsDto> getTemplateDefinitionList(
+        @EndpointLink("appslib/templateDefinitionLists") @BinderParam(BindToPath.class) EnterpriseDto enterprise,
+        @BinderParam(AppendToPath.class) Integer templateListId);
+
+    /**
+     * @see EnterpriseApi#getTemplateDefinitionList(EnterpriseDto, Integer)
+     */
+    @GET
+    @Consumes(TemplatesStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<TemplatesStateDto> listTemplateListStatus(
+        @EndpointLink("repositoryStatus") @BinderParam(BindToPath.class) TemplateDefinitionListDto templateList,
+        @QueryParam("datacenterId") @ParamParser(ParseDatacenterId.class) DatacenterDto datacenter);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EventApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EventApi.java
new file mode 100644
index 0000000..39b6055
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EventApi.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.event.options.EventOptions;
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.server.core.event.EventsDto;
+
+/**
+ * Provides synchronous access to Abiquo Event API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see EventAsyncApi
+ * @author Ignasi Barrera
+ * @author Vivien Mahé
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface EventApi
+{
+    /**
+     * List events.
+     * 
+     * @return The list of events.
+     */
+    EventsDto listEvents();
+
+    /**
+     * List events using filters.
+     * 
+     * @return The list of events using filters.
+     */
+    EventsDto listEvents(EventOptions options);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EventAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EventAsyncApi.java
new file mode 100644
index 0000000..ac7580d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/EventAsyncApi.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import org.jclouds.abiquo.domain.event.options.EventOptions;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.RequestFilters;
+
+import com.abiquo.server.core.event.EventsDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Abiquo Event API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see EventApi
+ * @author Ignasi Barrera
+ * @author Vivien Mahé
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+public interface EventAsyncApi
+{
+    /**
+     * @see EventApi#listEvents()
+     */
+    @GET
+    @Path("/events")
+    @Consumes(EventsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EventsDto> listEvents();
+
+    /**
+     * @see EventApi#listEvents()
+     */
+    @GET
+    @Path("/events")
+    @Consumes(EventsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<EventsDto> listEvents(EventOptions options);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/InfrastructureApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/InfrastructureApi.java
new file mode 100644
index 0000000..38d5723
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/InfrastructureApi.java
@@ -0,0 +1,1038 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.infrastructure.options.DatacenterOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.IpmiOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.MachineOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.StoragePoolOptions;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.domain.network.options.NetworkOptions;
+import org.jclouds.abiquo.domain.options.search.FilterOptions;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.abiquo.server.core.cloud.HypervisorTypesDto;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.BladeLocatorLedDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.abiquo.server.core.infrastructure.FsmsDto;
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+import com.abiquo.server.core.infrastructure.LogicServersDto;
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.MachineIpmiStateDto;
+import com.abiquo.server.core.infrastructure.MachineStateDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.OrganizationDto;
+import com.abiquo.server.core.infrastructure.OrganizationsDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.abiquo.server.core.infrastructure.RacksDto;
+import com.abiquo.server.core.infrastructure.RemoteServiceDto;
+import com.abiquo.server.core.infrastructure.RemoteServicesDto;
+import com.abiquo.server.core.infrastructure.UcsRackDto;
+import com.abiquo.server.core.infrastructure.UcsRacksDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpsDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.abiquo.server.core.infrastructure.network.VlanTagAvailabilityDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDevicesDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDevicesMetadataDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolsDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+
+/**
+ * Provides synchronous access to Abiquo Infrastructure API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see InfrastructureAsyncApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface InfrastructureApi
+{
+    /*********************** Datacenter ***********************/
+
+    /**
+     * List all datacenters.
+     * 
+     * @return The list of Datacenters.
+     */
+    DatacentersDto listDatacenters();
+
+    /**
+     * Create a new datacenter.
+     * 
+     * @param datacenter The datacenter to be created.
+     * @return The created datacenter.
+     */
+    DatacenterDto createDatacenter(DatacenterDto datacenter);
+
+    /**
+     * Get the given datacenter.
+     * 
+     * @param datacenterId The id of the datacenter.
+     * @return The datacenter or <code>null</code> if it does not exist.
+     */
+    DatacenterDto getDatacenter(Integer datacenterId);
+
+    /**
+     * Updates an existing datacenter.
+     * 
+     * @param datacenter The new attributes for the datacenter.
+     * @return The updated datacenter.
+     */
+    DatacenterDto updateDatacenter(DatacenterDto datacenter);
+
+    /**
+     * Deletes an existing datacenter.
+     * 
+     * @param datacenter The datacenter to delete.
+     */
+    void deleteDatacenter(DatacenterDto datacenter);
+
+    /**
+     * Retrieve remote machine information.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveremotemachineinformation</a>
+     * @param datacenter The datacenter.
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return The physical machine.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    MachineDto discoverSingleMachine(DatacenterDto datacenter, String ip,
+        HypervisorType hypervisorType, String user, String password);
+
+    /**
+     * Retrieve remote machine information.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrieveremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrieveremotemachineinformation</a>
+     * @param datacenter The datacenter.
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @param options Optional query params.
+     * @return The physical machine.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    MachineDto discoverSingleMachine(DatacenterDto datacenter, String ip,
+        HypervisorType hypervisorType, String user, String password, MachineOptions options);
+
+    /**
+     * Retrieve a list of remote machine information.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrievealistofremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrievealistofremotemachineinformation</a>
+     * @param datacenter The datacenter.
+     * @param ipFrom IP address of the remote first hypervisor to check.
+     * @param ipTo IP address of the remote last hypervisor to check.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return The physical machine list.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    MachinesDto discoverMultipleMachines(final DatacenterDto datacenter, final String ipFrom,
+        final String ipTo, final HypervisorType hypervisorType, final String user,
+        final String password);
+
+    /**
+     * Retrieve a list of remote machine information.
+     * 
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-Retrievealistofremotemachineinformation"
+     *      > http://community.abiquo.com/display/ABI20/DatacenterResource#DatacenterResource-
+     *      Retrievealistofremotemachineinformation</a>
+     * @param datacenter The datacenter.
+     * @param ipFrom IP address of the remote first hypervisor to check.
+     * @param ipTo IP address of the remote last hypervisor to check.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @param options Optional query params.
+     * @return The physical machine list.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    MachinesDto discoverMultipleMachines(final DatacenterDto datacenter, final String ipFrom,
+        final String ipTo, final HypervisorType hypervisorType, final String user,
+        final String password, final MachineOptions options);
+
+    /**
+     * Retreives limits for the given datacenter and any enterprise.
+     * 
+     * @param datacenter The datacenter.
+     * @return The usage limits for the datacenter on any enterprise.
+     */
+    DatacentersLimitsDto listLimits(DatacenterDto datacenter);
+
+    /**
+     * Check the state of a remote machine. This machine does not need to be managed by Abiquo.
+     * 
+     * @param datacenter The datacenter.
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return The physical machine state information.
+     */
+    MachineStateDto checkMachineState(DatacenterDto datacenter, String ip,
+        HypervisorType hypervisorType, String user, String password);
+
+    /**
+     * Check the state of a remote machine. This machine does not need to be managed by Abiquo.
+     * 
+     * @param datacenter The datacenter.
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param hypervisorType Kind of hypervisor we want to connect. Valid values are {vbox, kvm,
+     *            xen-3, vmx-04, hyperv-301, xenserver}.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @param options Optional query params.
+     * @return The physical machine state information.
+     */
+    MachineStateDto checkMachineState(DatacenterDto datacenter, String ip,
+        HypervisorType hypervisorType, String user, String password, MachineOptions options);
+
+    /**
+     * Check the ipmi configuration state of a remote machine. This machine does not need to be
+     * managed by Abiquo.
+     * 
+     * @param datacenter The datacenter.
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @return The ipmi configuration state information
+     */
+    MachineIpmiStateDto checkMachineIpmiState(DatacenterDto datacenter, String ip, String user,
+        String password);
+
+    /**
+     * Check the ipmi configuration state of a remote machine. This machine does not need to be
+     * managed by Abiquo.
+     * 
+     * @param datacenter The datacenter.
+     * @param ip IP address of the remote hypervisor to connect.
+     * @param user User to log in.
+     * @param password Password to authenticate.
+     * @param options Optional query params.
+     * @return The ipmi configuration state information
+     */
+    MachineIpmiStateDto checkMachineIpmiState(DatacenterDto datacenter, String ip, String user,
+        String password, IpmiOptions options);
+
+    /*********************** Hypervisor ***********************/
+
+    /**
+     * Retreives the hypervisor type of a remote a machine.
+     * 
+     * @param datacenter The datacenter.
+     * @param options Optional query params.
+     * @return The hypervisor type.
+     */
+    String getHypervisorTypeFromMachine(DatacenterDto datacenter, DatacenterOptions options);
+
+    /**
+     * Retreives the hypervisor types in the datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @return The hypervisor types.
+     */
+    HypervisorTypesDto getHypervisorTypes(DatacenterDto datacenter);
+
+    /*********************** Unmanaged Rack ********************** */
+
+    /**
+     * List all not managed racks for a datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @return The list of not managed racks for the datacenter.
+     */
+    RacksDto listRacks(DatacenterDto datacenter);
+
+    /**
+     * Create a new not managed rack in a datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @param rack The rack to be created.
+     * @return The created rack.
+     */
+    RackDto createRack(final DatacenterDto datacenter, final RackDto rack);
+
+    /**
+     * Get the given rack from the given datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @param rackId The id of the rack.
+     * @return The rack or <code>null</code> if it does not exist.
+     */
+    RackDto getRack(DatacenterDto datacenter, Integer rackId);
+
+    /**
+     * Updates an existing rack from the given datacenter.
+     * 
+     * @param rack The new attributes for the rack.
+     * @return The updated rack.
+     */
+    RackDto updateRack(final RackDto rack);
+
+    /**
+     * Deletes an existing rack.
+     * 
+     * @param rack The rack to delete.
+     */
+    void deleteRack(final RackDto rack);
+
+    /*********************** Managed Rack **********************/
+
+    /**
+     * List all managed racks for a datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @return The list of managed racks for the datacenter.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+    UcsRacksDto listManagedRacks(DatacenterDto datacenter);
+
+    /**
+     * Create a new managed rack in a datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @param rack The managed rack to be created.
+     * @return The created rack.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    UcsRackDto createManagedRack(final DatacenterDto datacenter, final UcsRackDto rack);
+
+    /**
+     * Get the given managed rack from the given datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @param rackId The id of the rack.
+     * @return The rack or <code>null</code> if it does not exist.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+    UcsRackDto getManagedRack(DatacenterDto datacenter, Integer rackId);
+
+    /**
+     * Updates an existing managed rack from the given datacenter.
+     * 
+     * @param rack The new attributes for the rack.
+     * @return The updated rack.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    UcsRackDto updateManagedRack(final UcsRackDto rack);
+
+    /**
+     * List all service profiles of the ucs rack.
+     * 
+     * @param rack The ucs rack.
+     * @return The list of service profiles for the rack.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    LogicServersDto listServiceProfiles(UcsRackDto rack);
+
+    /**
+     * List service profiles of the ucs rack with filtering options.
+     * 
+     * @param rack The ucs rack.
+     * @param options Optional query params.
+     * @return The list of service profiles for the rack.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    LogicServersDto listServiceProfiles(UcsRackDto rack, FilterOptions options);
+
+    /**
+     * List all service profile templates of the ucs rack.
+     * 
+     * @param rack The ucs rack.
+     * @return The list of service profile templates for the rack.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    LogicServersDto listServiceProfileTemplates(UcsRackDto rack);
+
+    /**
+     * List all service profile templates of the ucs rack with options.
+     * 
+     * @param rack The ucs rack.
+     * @param options Optional query params.
+     * @return The list of service profile templates for the rack.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    LogicServersDto listServiceProfileTemplates(UcsRackDto rack, FilterOptions options);
+
+    /**
+     * List all organizations of the ucs rack.
+     * 
+     * @param rack The ucs rack.
+     * @return The list of organizations for the rack.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    OrganizationsDto listOrganizations(UcsRackDto rack);
+
+    /**
+     * List all organizations of the ucs rack with options.
+     * 
+     * @param rack The ucs rack.
+     * @param options Optional query params.
+     * @return The list of organizations for the rack.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    OrganizationsDto listOrganizations(UcsRackDto rack, FilterOptions options);
+
+    /**
+     * Clone a service profile.
+     * 
+     * @param rack The managed rack where thw service profile will be created.
+     * @param logicServer The original logic server.
+     * @param organization The organization to be associated.
+     * @param newName The name of the new service profile.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    void cloneLogicServer(UcsRackDto rack, LogicServerDto logicServer,
+        OrganizationDto organization, String newName);
+
+    /**
+     * Delete a service profile.
+     * 
+     * @param rack The managed rack where the service profile will be created.
+     * @param logicServer The original logic server.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    void deleteLogicServer(UcsRackDto rack, LogicServerDto logicServer);
+
+    /**
+     * Associate a service profile with a blade.
+     * 
+     * @param rack The managed rack where the service profile is.
+     * @param logicServer The logic server.
+     * @param organization The organization to be associated.
+     * @param bladeName The name of the blade.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    void associateLogicServer(UcsRackDto rack, LogicServerDto logicServer,
+        OrganizationDto organization, String bladeName);
+
+    /**
+     * Associate a service profile with a blade instantiating a service profile template.
+     * 
+     * @param rack The managed rack where the service profile is.
+     * @param logicServer The logic server.
+     * @param organization The organization to be associated.
+     * @param newName Name of the new service profile.
+     * @param bladeName The name of the blade.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    void associateTemplate(UcsRackDto rack, LogicServerDto logicServer,
+        OrganizationDto organization, String newName, String bladeName);
+
+    /**
+     * Clone a service profile and associate it with a blade.
+     * 
+     * @param rack The managed rack where the service profile is.
+     * @param logicServer The logic server.
+     * @param organization The organization to be associated.
+     * @param newName Name of the new service profile.
+     * @param bladeName The name of the blade.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    void cloneAndAssociateLogicServer(UcsRackDto rack, LogicServerDto logicServer,
+        OrganizationDto organization, String newName, String bladeName);
+
+    /**
+     * Dissociate a service profile from a blade.
+     * 
+     * @param rack The managed rack where the service profile is.
+     * @param logicServer The logic server.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    void dissociateLogicServer(UcsRackDto rack, LogicServerDto logicServer);
+
+    /**
+     * Get FSM list of an entity
+     * 
+     * @param rack The managed rack where the entity belongs.
+     * @param dn Distinguished name of the entity.
+     * @param fsm The fsm.
+     */
+    @EnterpriseEdition
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    FsmsDto listFsms(UcsRackDto rack, String dn);
+
+    /*********************** Remote Service ********************** */
+
+    /**
+     * List all remote services of the datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @return The list of remote services for the datacenter.
+     */
+    RemoteServicesDto listRemoteServices(DatacenterDto dataceter);
+
+    /**
+     * Create a new remote service in a datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @param remoteService The remote service to be created.
+     * @return The created remote service.
+     */
+    RemoteServiceDto createRemoteService(final DatacenterDto datacenter,
+        final RemoteServiceDto remoteService);
+
+    /**
+     * Get the given remote service from the given datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @param remoteServiceType The type of the remote service.
+     * @return The remote service or <code>null</code> if it does not exist.
+     */
+    RemoteServiceDto getRemoteService(DatacenterDto datacenter, RemoteServiceType remoteServiceType);
+
+    /**
+     * Updates an existing remote service from the given datacenter.
+     * 
+     * @param remoteService The new attributes for the remote service.
+     * @return The updated remote service.
+     */
+    RemoteServiceDto updateRemoteService(RemoteServiceDto remoteService);
+
+    /**
+     * Deletes an existing remote service.
+     * 
+     * @param remoteService The remote service to delete.
+     */
+    void deleteRemoteService(RemoteServiceDto remoteService);
+
+    /**
+     * Check if the given remote service is available and properly configured.
+     * 
+     * @param remoteService The remote service to check.
+     * @return A Boolean indicating if the remote service is available.
+     */
+    boolean isAvailable(RemoteServiceDto remoteService);
+
+    /*********************** Machine ********************** */
+
+    /**
+     * Create a new physical machine in a rack.
+     * 
+     * @param rack The rack.
+     * @param machine The physical machine to be created.
+     * @return The created physical machine.
+     */
+    MachineDto createMachine(RackDto rack, MachineDto machine);
+
+    /**
+     * Get the given machine from the given rack.
+     * 
+     * @param rack The rack.
+     * @param machineId The id of the machine.
+     * @return The machine or <code>null</code> if it does not exist.
+     */
+    MachineDto getMachine(RackDto rack, Integer machineId);
+
+    /**
+     * Checks the real infrastructure state for the given physical machine. The machine is updated
+     * with the result state.
+     * 
+     * @param machine The machine to check
+     * @paran boolean that indicates a database synchronization
+     * @return A machineStateDto with a machine state value from enum MachineState
+     */
+    MachineStateDto checkMachineState(MachineDto machine, boolean sync);
+
+    /**
+     * Checks the ipmi configuration state for the given physical machine.
+     * 
+     * @param machine The machine to check
+     * @return A machineIpmiStateDto with a machine ipmi configuration state value from enum
+     *         MachineState
+     */
+    MachineIpmiStateDto checkMachineIpmiState(MachineDto machine);
+
+    /**
+     * Updates an existing physical machine.
+     * 
+     * @param machine The new attributes for the physical machine.
+     * @return The updated machine.
+     */
+    MachineDto updateMachine(MachineDto machine);
+
+    /**
+     * Deletes an existing physical machine.
+     * 
+     * @param machine The physical machine to delete.
+     */
+    void deleteMachine(MachineDto machine);
+
+    /**
+     * Reserve the given machine for the given enterprise.
+     * 
+     * @param enterprise The enterprise reserving the machine.
+     * @param machine The machine to reserve.
+     * @return The reserved machine.
+     */
+    MachineDto reserveMachine(EnterpriseDto enterprise, MachineDto machine);
+
+    /**
+     * Cancels the reservation of the given machine.
+     * 
+     * @param enterprise The enterprise to cancel reservation.
+     * @param machine The machine to release.
+     */
+    Void cancelReservation(EnterpriseDto enterprise, MachineDto machine);
+
+    /**
+     * List all machines racks for a rack.
+     * 
+     * @param rack The rack.
+     * @return The list of physical machines for the rack.
+     */
+    MachinesDto listMachines(RackDto rack);
+
+    /*********************** Blade ***********************/
+
+    /**
+     * Power off a physical machine in a UCS rack.
+     * 
+     * @param machime The phyisical machine.
+     */
+    @EnterpriseEdition
+    void powerOff(MachineDto machine);
+
+    /**
+     * Power on a physical machine in a UCS rack.
+     * 
+     * @param machime The phyisical machine.
+     */
+    @EnterpriseEdition
+    void powerOn(MachineDto machine);
+
+    /**
+     * Get the logic server associated with a machine in a Cisc UCS rack.
+     * 
+     * @param machime The phyisical machine.
+     * @return The logic server.
+     */
+    @EnterpriseEdition
+    LogicServerDto getLogicServer(MachineDto machine);
+
+    /**
+     * Turn off locator led of a physical machine in a UCS rack.
+     * 
+     * @param machime The phyisical machine.
+     */
+    @EnterpriseEdition
+    void ledOn(MachineDto machine);
+
+    /**
+     * Light locator led of a physical machine in a UCS rack.
+     * 
+     * @param machime The phyisical machine.
+     */
+    @EnterpriseEdition
+    void ledOff(MachineDto machine);
+
+    /**
+     * Get led locator info from a physical machine in a UCS rack.
+     * 
+     * @param machime The phyisical machine.
+     * @return Led locator information.
+     */
+    @EnterpriseEdition
+    BladeLocatorLedDto getLocatorLed(MachineDto machine);
+
+    /**
+     * List all virtual machines in a physical machine.
+     * 
+     * @param machine The physical machine.
+     * @return The list of virtual machines in the physical machine.
+     */
+    VirtualMachinesWithNodeExtendedDto listVirtualMachinesByMachine(MachineDto machine,
+        MachineOptions options);
+
+    /**
+     * Get the given virtual machine
+     * 
+     * @param machine
+     * @param virtualMachineId
+     * @return
+     */
+    VirtualMachineWithNodeExtendedDto getVirtualMachine(MachineDto machine, Integer virtualMachineId);
+
+    /*********************** Storage Device ***********************/
+
+    /**
+     * List all storage devices of the datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @return The list of storage devices in the datacenter.
+     */
+    @EnterpriseEdition
+    StorageDevicesDto listStorageDevices(DatacenterDto datacenter);
+
+    /**
+     * List all supported storage devices.
+     * 
+     * @param datacenter The datacenter.
+     * @return The list of supported storage devices.
+     */
+    @EnterpriseEdition
+    StorageDevicesMetadataDto listSupportedStorageDevices(DatacenterDto datacenter);
+
+    /**
+     * Get the storage device.
+     * 
+     * @param storageDeviceId The id of the storage device.
+     * @return The storage device or <code>null</code> if it does not exist.
+     */
+    @EnterpriseEdition
+    StorageDeviceDto getStorageDevice(DatacenterDto datacenter, Integer storageDeviceId);
+
+    /**
+     * Create a new storage device.
+     * 
+     * @param datacenter The datacenter.
+     * @param storageDevice The storage device to be created.
+     * @return The created storage device.
+     */
+    @EnterpriseEdition
+    StorageDeviceDto createStorageDevice(final DatacenterDto datacenter,
+        final StorageDeviceDto storageDevice);
+
+    /**
+     * Deletes an existing storage device.
+     * 
+     * @param storageDevice The storage device to delete.
+     */
+    @EnterpriseEdition
+    void deleteStorageDevice(StorageDeviceDto storageDevice);
+
+    /**
+     * Updates an existing storage device.
+     * 
+     * @param storageDevice The new attributes for the storage device.
+     * @return The updated storage device.
+     */
+    @EnterpriseEdition
+    StorageDeviceDto updateStorageDevice(StorageDeviceDto storageDevice);
+
+    /*********************** Tier ***********************/
+    /**
+     * List all tiers of the datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @return The list of tiers in the datacenter.
+     */
+    @EnterpriseEdition
+    TiersDto listTiers(DatacenterDto datacenter);
+
+    /**
+     * Updates a tier.
+     * 
+     * @param tier The new attributes for the tier.
+     * @return The updated tier.
+     */
+    @EnterpriseEdition
+    TierDto updateTier(TierDto tier);
+
+    /**
+     * Get the tier.
+     * 
+     * @param tierId The id of the tier.
+     * @return The tier or <code>null</code> if it does not exist.
+     */
+    @EnterpriseEdition
+    TierDto getTier(DatacenterDto datacenter, Integer tierId);
+
+    /*********************** Storage Pool ***********************/
+
+    /**
+     * List storage pools on a storage device.
+     * 
+     * @param storageDevice The storage device.
+     * @param options Optional query params.
+     * @return The list of storage pools in the storage device.
+     */
+    @EnterpriseEdition
+    StoragePoolsDto listStoragePools(StorageDeviceDto storageDeviceDto,
+        StoragePoolOptions storagePoolOptions);
+
+    /**
+     * List storage pools on a tier.
+     * 
+     * @param tier The tier device.
+     * @return The list of storage pools in the tier.
+     */
+    @EnterpriseEdition
+    StoragePoolsDto listStoragePools(TierDto tier);
+
+    /**
+     * Create a new storage pool in a storage device.
+     * 
+     * @param storageDevice The storage device.
+     * @param storagePool The storage pool to be created.
+     * @return The created storage pool.
+     */
+    @EnterpriseEdition
+    StoragePoolDto createStoragePool(StorageDeviceDto storageDevice, StoragePoolDto storagePool);
+
+    /**
+     * Updates a storage pool.
+     * 
+     * @param storagePool The new attributes for the storage pool.
+     * @return The updated tier.
+     */
+    @EnterpriseEdition
+    StoragePoolDto updateStoragePool(StoragePoolDto storagePool);
+
+    /**
+     * Deletes an existing storage pool.
+     * 
+     * @param storagePool The storage pool to delete.
+     */
+    @EnterpriseEdition
+    void deleteStoragePool(StoragePoolDto storagePool);
+
+    /**
+     * Get the storage pool.
+     * 
+     * @param storageDevice The storage device.
+     * @param storagePoolId The id of the storage pool.
+     * @return The storage pool or <code>null</code> if it does not exist.
+     */
+    @EnterpriseEdition
+    StoragePoolDto getStoragePool(StorageDeviceDto storageDevice, String storagePoolId);
+
+    /**
+     * Refresh the given storage pool data.
+     * 
+     * @param storagePool The storage pool to refresh.
+     * @param options The options to query the storage pool.
+     * @return The updated storage pool.
+     */
+    @EnterpriseEdition
+    StoragePoolDto refreshStoragePool(StoragePoolDto storagePool, StoragePoolOptions options);
+
+    /*********************** Network ***********************/
+
+    /**
+     * List all public, external and not managed networks of a datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @return The list of not public, external and not managed for the datacenter.
+     */
+    @EnterpriseEdition
+    VLANNetworksDto listNetworks(DatacenterDto datacenter);
+
+    /**
+     * List networks of a datacenter with options.
+     * 
+     * @param datacenter The datacenter.
+     * @param options Optional query params.
+     * @return The list of not public, external and not managed for the datacenter.
+     */
+    @EnterpriseEdition
+    VLANNetworksDto listNetworks(DatacenterDto datacenter, NetworkOptions options);
+
+    /**
+     * Get the given network from the given datacenter.
+     * 
+     * @param datacenter The datacenter.
+     * @param networkId The id of the network.
+     * @return The rack or <code>null</code> if it does not exist.
+     */
+    VLANNetworkDto getNetwork(DatacenterDto datacenter, Integer networkId);
+
+    /**
+     * Create a new public network.
+     * 
+     * @param storageDevice The storage device.
+     * @param storagePool The storage pool to be created.
+     * @return The created storage pool.
+     */
+    @EnterpriseEdition
+    VLANNetworkDto createNetwork(DatacenterDto datacenter, VLANNetworkDto network);
+
+    /**
+     * Updates a network.
+     * 
+     * @param network The new attributes for the network.
+     * @return The updated tier.
+     */
+    @EnterpriseEdition
+    VLANNetworkDto updateNetwork(VLANNetworkDto network);
+
+    /**
+     * Deletes an existing network.
+     * 
+     * @param network The network to delete.
+     */
+    @EnterpriseEdition
+    void deleteNetwork(VLANNetworkDto network);
+
+    /**
+     * Check the availability of a tag.
+     * 
+     * @param datacenter The datacenter.
+     * @param tag Tag to check.
+     * @return A tag availability object.
+     */
+    @EnterpriseEdition
+    VlanTagAvailabilityDto checkTagAvailability(DatacenterDto datacenter, Integer tag);
+
+    /*********************** Network IPs ***********************/
+
+    /**
+     * List all the IPs in the given public network.
+     * 
+     * @param network The public network.
+     * @return The IPs in the given public network.
+     * @since 2.3
+     */
+    PublicIpsDto listPublicIps(VLANNetworkDto network);
+
+    /**
+     * List all the IPs in the given public network.
+     * 
+     * @param network The public network.
+     * @param options The filtering options.
+     * @return The IPs in the given public network.
+     * @since 2.3
+     */
+    PublicIpsDto listPublicIps(VLANNetworkDto network, IpOptions options);
+
+    /**
+     * Get the given public ip.
+     * 
+     * @param network The public network.
+     * @param ipId The id of the ip to get.
+     * @return The requested ip.
+     * @since 2.3
+     */
+    PublicIpDto getPublicIp(VLANNetworkDto network, Integer ipId);
+
+    /**
+     * List all the IPs in the given external network.
+     * 
+     * @param network The external network.
+     * @return The IPs in the given external network.
+     * @since 2.3
+     */
+    ExternalIpsDto listExternalIps(VLANNetworkDto network);
+
+    /**
+     * List all the IPs in the given external network.
+     * 
+     * @param network The external network.
+     * @param options The filtering options.
+     * @return The IPs in the given external network.
+     * @since 2.3
+     */
+    ExternalIpsDto listExternalIps(VLANNetworkDto network, IpOptions options);
+
+    /**
+     * Get the given external ip.
+     * 
+     * @param network The external network.
+     * @param ipId The id of the ip to get.
+     * @return The requested ip.
+     * @since 2.3
+     */
+    ExternalIpDto getExternalIp(VLANNetworkDto network, Integer ipId);
+
+    /**
+     * List all the IPs in the given unmanaged network.
+     * 
+     * @param network The unmanaged network.
+     * @return The IPs in the given unmanaged network.
+     * @since 2.3
+     */
+    UnmanagedIpsDto listUnmanagedIps(VLANNetworkDto network);
+
+    /**
+     * List all the IPs in the given unmanaged network.
+     * 
+     * @param network The unmanaged network.
+     * @param options The filtering options.
+     * @return The IPs in the given unmanaged network.
+     * @since 2.3
+     */
+    UnmanagedIpsDto listUnmanagedIps(VLANNetworkDto network, IpOptions options);
+
+    /**
+     * Get the given unmanaged ip.
+     * 
+     * @param network The unmanaged network.
+     * @param ipId The id of the ip to get.
+     * @return The requested ip.
+     * @since 2.3
+     */
+    UnmanagedIpDto getUnmanagedIp(VLANNetworkDto network, Integer ipId);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/InfrastructureAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/InfrastructureAsyncApi.java
new file mode 100644
index 0000000..892b79b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/InfrastructureAsyncApi.java
@@ -0,0 +1,1110 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.abiquo.binders.AppendToPath;
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.abiquo.binders.BindToXMLPayloadAndPath;
+import org.jclouds.abiquo.binders.infrastructure.AppendMachineIdToPath;
+import org.jclouds.abiquo.binders.infrastructure.AppendRemoteServiceTypeToPath;
+import org.jclouds.abiquo.binders.infrastructure.BindSupportedDevicesLinkToPath;
+import org.jclouds.abiquo.binders.infrastructure.ucs.BindLogicServerParameters;
+import org.jclouds.abiquo.binders.infrastructure.ucs.BindOrganizationParameters;
+import org.jclouds.abiquo.domain.infrastructure.options.DatacenterOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.IpmiOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.MachineOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.StoragePoolOptions;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.domain.network.options.NetworkOptions;
+import org.jclouds.abiquo.domain.options.search.FilterOptions;
+import org.jclouds.abiquo.functions.ReturnAbiquoExceptionOnNotFoundOr4xx;
+import org.jclouds.abiquo.functions.ReturnFalseIfNotAvailable;
+import org.jclouds.abiquo.functions.infrastructure.ParseDatacenterId;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.abiquo.reference.annotations.EnterpriseEdition;
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.http.functions.ReturnStringIf2xx;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.ParamParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.abiquo.server.core.cloud.HypervisorTypesDto;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.BladeLocatorLedDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.abiquo.server.core.infrastructure.FsmsDto;
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+import com.abiquo.server.core.infrastructure.LogicServersDto;
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.MachineIpmiStateDto;
+import com.abiquo.server.core.infrastructure.MachineStateDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.OrganizationDto;
+import com.abiquo.server.core.infrastructure.OrganizationsDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.abiquo.server.core.infrastructure.RacksDto;
+import com.abiquo.server.core.infrastructure.RemoteServiceDto;
+import com.abiquo.server.core.infrastructure.RemoteServicesDto;
+import com.abiquo.server.core.infrastructure.UcsRackDto;
+import com.abiquo.server.core.infrastructure.UcsRacksDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpsDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.abiquo.server.core.infrastructure.network.VlanTagAvailabilityDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDevicesDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDevicesMetadataDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolsDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Abiquo Infrastructure API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see InfrastructureApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+@Path("/admin")
+public interface InfrastructureAsyncApi
+{
+    /*********************** Datacenter ***********************/
+
+    /**
+     * @see InfrastructureApi#listDatacenters()
+     */
+    @GET
+    @Path("/datacenters")
+    @Consumes(DatacentersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DatacentersDto> listDatacenters();
+
+    /**
+     * @see InfrastructureApi#createDatacenter(DatacenterDto)
+     */
+    @POST
+    @Path("/datacenters")
+    @Produces(DatacenterDto.BASE_MEDIA_TYPE)
+    @Consumes(DatacenterDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DatacenterDto> createDatacenter(
+        @BinderParam(BindToXMLPayload.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#getDatacenter(Integer)
+     */
+    @GET
+    @Path("/datacenters/{datacenter}")
+    @Consumes(DatacenterDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<DatacenterDto> getDatacenter(@PathParam("datacenter") Integer datacenterId);
+
+    /**
+     * @see InfrastructureApi#updateDatacenter(DatacenterDto)
+     */
+    @PUT
+    @Produces(DatacenterDto.BASE_MEDIA_TYPE)
+    @Consumes(DatacenterDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DatacenterDto> updateDatacenter(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#deleteDatacenter(DatacenterDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteDatacenter(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#discoverSingleMachine(DatacenterDto, String, HypervisorType, String,
+     *      String)
+     */
+    @GET
+    @Consumes(MachineDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnAbiquoExceptionOnNotFoundOr4xx.class)
+    ListenableFuture<MachineDto> discoverSingleMachine(
+        @EndpointLink("discoversingle") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @QueryParam("ip") String ip, @QueryParam("hypervisor") HypervisorType hypervisorType,
+        @QueryParam("user") String user, @QueryParam("password") String password);
+
+    /**
+     * @see InfrastructureApi#discoverSingleMachine(DatacenterDto, String, HypervisorType, String,
+     *      String, MachineOptions)
+     */
+    @GET
+    @Consumes(MachineDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnAbiquoExceptionOnNotFoundOr4xx.class)
+    ListenableFuture<MachineDto> discoverSingleMachine(
+        @EndpointLink("discoversingle") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @QueryParam("ip") String ip, @QueryParam("hypervisor") HypervisorType hypervisorType,
+        @QueryParam("user") String user, @QueryParam("password") String password,
+        MachineOptions options);
+
+    /**
+     * @see InfrastructureApi#discoverMultipleMachines(DatacenterDto, String, String,
+     *      HypervisorType, String, String)
+     */
+    @GET
+    @Consumes(MachinesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnAbiquoExceptionOnNotFoundOr4xx.class)
+    ListenableFuture<MachineDto> discoverMultipleMachines(
+        @EndpointLink("discovermultiple") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @QueryParam("ipFrom") String ipFrom, @QueryParam("ipTo") String ipTo,
+        @QueryParam("hypervisor") HypervisorType hypervisorType, @QueryParam("user") String user,
+        @QueryParam("password") String password);
+
+    /**
+     * @see InfrastructureApi#discoverMultipleMachines(DatacenterDto, String, String,
+     *      HypervisorType, String, String, MachineOptions)
+     */
+    @GET
+    @Consumes(MachinesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnAbiquoExceptionOnNotFoundOr4xx.class)
+    ListenableFuture<MachineDto> discoverMultipleMachines(
+        @EndpointLink("discovermultiple") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @QueryParam("ipFrom") String ipFrom, @QueryParam("ipTo") String ipTo,
+        @QueryParam("hypervisor") HypervisorType hypervisorType, @QueryParam("user") String user,
+        @QueryParam("password") String password, MachineOptions options);
+
+    /**
+     * @see InfrastructureApi#listLimits(DatacenterDto)
+     */
+    @GET
+    @Consumes(DatacentersLimitsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<DatacentersLimitsDto> listLimits(
+        @EndpointLink("getLimits") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#checkMachineState(DatacenterDto, String, String, HypervisorType,
+     *      String, String)
+     */
+    @GET
+    @Consumes(MachineStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnAbiquoExceptionOnNotFoundOr4xx.class)
+    ListenableFuture<MachineStateDto> checkMachineState(
+        @EndpointLink("checkmachinestate") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @QueryParam("ip") String ip, @QueryParam("hypervisor") HypervisorType hypervisorType,
+        @QueryParam("user") String user, @QueryParam("password") String password);
+
+    /**
+     * @see InfrastructureApi#checkMachineState(DatacenterDto, String, String, HypervisorType,
+     *      String, String, MachineOptions)
+     */
+    @GET
+    @Consumes(MachineStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnAbiquoExceptionOnNotFoundOr4xx.class)
+    ListenableFuture<MachineStateDto> checkMachineState(
+        @EndpointLink("checkmachinestate") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @QueryParam("ip") String ip, @QueryParam("hypervisor") HypervisorType hypervisorType,
+        @QueryParam("user") String user, @QueryParam("password") String password,
+        MachineOptions options);
+
+    /**
+     * @see InfrastructureApi#checkMachineIpmiState(DatacenterDto, String, String, String)
+     */
+    @GET
+    @Consumes(MachineIpmiStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnAbiquoExceptionOnNotFoundOr4xx.class)
+    ListenableFuture<MachineIpmiStateDto> checkMachineIpmiState(
+        @EndpointLink("checkmachineipmistate") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @QueryParam("ip") String ip, @QueryParam("user") String user,
+        @QueryParam("password") String password);
+
+    /**
+     * @see InfrastructureApi#checkMachineIpmiState(DatacenterDto, String, String, String,
+     *      IpmiOptions)
+     */
+    @GET
+    @Consumes(MachineIpmiStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnAbiquoExceptionOnNotFoundOr4xx.class)
+    ListenableFuture<MachineIpmiStateDto> checkMachineIpmiState(
+        @EndpointLink("checkmachineipmistate") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @QueryParam("ip") String ip, @QueryParam("user") String user,
+        @QueryParam("password") String password, IpmiOptions options);
+
+    /*********************** Hypervisor ***********************/
+    /**
+     * @see InfrastructureApi#getHypervisorTypeFromMachine(DatacenterDto, DatacenterOptions)
+     */
+    @GET
+    @Consumes(MediaType.TEXT_PLAIN)
+    @ResponseParser(ReturnStringIf2xx.class)
+    ListenableFuture<String> getHypervisorTypeFromMachine(
+        @EndpointLink("hypervisor") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        DatacenterOptions options);
+
+    /**
+     * @see InfrastructureApi#getHypervisorTypes(DatacenterDto)
+     */
+    @GET
+    @Consumes(HypervisorTypesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<HypervisorTypesDto> getHypervisorTypes(
+        @EndpointLink("hypervisors") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /*********************** Unmanaged Rack ***********************/
+
+    /**
+     * @see InfrastructureApi#listRacks(DatacenterDto)
+     */
+    @GET
+    @Consumes(RacksDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RacksDto> listRacks(
+        @EndpointLink("racks") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#createRack(DatacenterDto, RackDto)
+     */
+    @POST
+    @Produces(RackDto.BASE_MEDIA_TYPE)
+    @Consumes(RackDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RackDto> createRack(
+        @EndpointLink("racks") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(BindToXMLPayload.class) RackDto rack);
+
+    /**
+     * @see InfrastructureApi#getRack(DatacenterDto, Integer)
+     */
+    @GET
+    @Consumes(RackDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<RackDto> getRack(
+        @EndpointLink("racks") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(AppendToPath.class) Integer rackId);
+
+    /**
+     * @see InfrastructureApi#updateRack(RackDto)
+     */
+    @PUT
+    @Consumes(RackDto.BASE_MEDIA_TYPE)
+    @Produces(RackDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RackDto> updateRack(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) RackDto rack);
+
+    /**
+     * @see InfrastructureApi#deleteRack(RackDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteRack(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) RackDto rack);
+
+    /*********************** Managed Rack ***********************/
+
+    /**
+     * @see InfrastructureApi#listManagedRacks(DatacenterDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(UcsRacksDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UcsRacksDto> listManagedRacks(
+        @EndpointLink("racks") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#createManagedRack(DatacenterDto, UcsRackDto)
+     */
+    @EnterpriseEdition
+    @POST
+    @Produces(UcsRackDto.BASE_MEDIA_TYPE)
+    @Consumes(UcsRackDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UcsRackDto> createManagedRack(
+        @EndpointLink("racks") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(BindToXMLPayload.class) UcsRackDto rack);
+
+    /**
+     * @see InfrastructureApi#getManagedRack(DatacenterDto, Integer)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(UcsRackDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<UcsRackDto> getManagedRack(
+        @EndpointLink("racks") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(AppendToPath.class) Integer rackId);
+
+    /**
+     * @see InfrastructureApi#updateManagedRack(UcsRackDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    @Consumes(UcsRackDto.BASE_MEDIA_TYPE)
+    @Produces(UcsRackDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UcsRackDto> updateManagedRack(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) UcsRackDto rack);
+
+    /**
+     * @see InfrastructureApi#listServiceProfiles(UcsRackDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(LogicServersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<LogicServersDto> listServiceProfiles(
+        @EndpointLink("logicservers") @BinderParam(BindToPath.class) UcsRackDto rack);
+
+    /**
+     * @see InfrastructureApi#listServiceProfiles(UcsRackDto, QueryOptions)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(LogicServersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<LogicServersDto> listServiceProfiles(
+        @EndpointLink("logicservers") @BinderParam(BindToPath.class) UcsRackDto rack,
+        FilterOptions options);
+
+    /**
+     * @see InfrastructureApi#listServiceProfileTemplates(UcsRackDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(LogicServersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<LogicServersDto> listServiceProfileTemplates(
+        @EndpointLink("ls-templates") @BinderParam(BindToPath.class) UcsRackDto rack);
+
+    /**
+     * @see InfrastructureApi#listServiceProfileTemplates(UcsRackDto, LogicServerOptions)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(LogicServersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<LogicServersDto> listServiceProfileTemplates(
+        @EndpointLink("ls-templates") @BinderParam(BindToPath.class) UcsRackDto rack,
+        FilterOptions options);
+
+    /**
+     * @see InfrastructureApi#listOrganizations(UcsRackDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(OrganizationsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<OrganizationsDto> listOrganizations(
+        @EndpointLink("organizations") @BinderParam(BindToPath.class) UcsRackDto rack);
+
+    /**
+     * @see InfrastructureApi#listOrganizations(UcsRackDto, OrganizationOptions)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(OrganizationsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<OrganizationsDto> listOrganizations(
+        @EndpointLink("organizations") @BinderParam(BindToPath.class) UcsRackDto rack,
+        FilterOptions options);
+
+    /**
+     * @see InfrastructureApi#cloneLogicServer(UcsRackDto, LogicServerDto, OrganizationDto, String)
+     */
+    @EnterpriseEdition
+    @POST
+    ListenableFuture<Void> cloneLogicServer(
+        @EndpointLink("ls-clone") @BinderParam(BindToPath.class) UcsRackDto rack,
+        @BinderParam(BindLogicServerParameters.class) LogicServerDto logicServer,
+        @BinderParam(BindOrganizationParameters.class) OrganizationDto organization,
+        @QueryParam("newName") String newName);
+
+    /**
+     * @see InfrastructureApi#associateLogicServer(UcsRackDto, LogicServerDto, OrganizationDto,
+     *      String)
+     */
+    @EnterpriseEdition
+    @POST
+    ListenableFuture<Void> associateLogicServer(
+        @EndpointLink("ls-associate") @BinderParam(BindToPath.class) UcsRackDto rack,
+        @BinderParam(BindLogicServerParameters.class) LogicServerDto logicServer,
+        @BinderParam(BindOrganizationParameters.class) OrganizationDto organization,
+        @QueryParam("bladeDn") String bladeName);
+
+    /**
+     * @see InfrastructureApi#associateTemplate(UcsRackDto, LogicServerDto, OrganizationDto, String,
+     *      String)
+     */
+    @EnterpriseEdition
+    @POST
+    ListenableFuture<Void> associateTemplate(
+        @EndpointLink("ls-associatetemplate") @BinderParam(BindToPath.class) UcsRackDto rack,
+        @BinderParam(BindLogicServerParameters.class) LogicServerDto logicServer,
+        @BinderParam(BindOrganizationParameters.class) OrganizationDto organization,
+        @QueryParam("newName") String newName, @QueryParam("bladeDn") String bladeName);
+
+    /**
+     * @see InfrastructureApi#cloneAndAssociateLogicServer(UcsRackDto, LogicServerDto,
+     *      OrganizationDto, String, String)
+     */
+    @EnterpriseEdition
+    @POST
+    ListenableFuture<Void> cloneAndAssociateLogicServer(
+        @EndpointLink("ls-associateclone") @BinderParam(BindToPath.class) UcsRackDto rack,
+        @BinderParam(BindLogicServerParameters.class) LogicServerDto logicServer,
+        @BinderParam(BindOrganizationParameters.class) OrganizationDto organization,
+        @QueryParam("newName") String newName, @QueryParam("bladeDn") String bladeName);
+
+    /**
+     * @see InfrastructureApi#dissociateLogicServer(UcsRackDto, LogicServerDto)
+     */
+    @EnterpriseEdition
+    @POST
+    ListenableFuture<Void> dissociateLogicServer(
+        @EndpointLink("ls-dissociate") @BinderParam(BindToPath.class) UcsRackDto rack,
+        @BinderParam(BindLogicServerParameters.class) LogicServerDto logicServer);
+
+    /**
+     * @see InfrastructureApi#deleteLogicServer(UcsRackDto, LogicServerDto)
+     */
+    @EnterpriseEdition
+    @POST
+    ListenableFuture<Void> deleteLogicServer(
+        @EndpointLink("ls-delete") @BinderParam(BindToPath.class) UcsRackDto rack,
+        @BinderParam(BindLogicServerParameters.class) LogicServerDto logicServer);
+
+    /**
+     * @see InfrastructureApi#listFsms(UcsRackDto, String)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(FsmsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<FsmsDto> listFsms(
+        @EndpointLink("fsm") @BinderParam(BindToPath.class) UcsRackDto rack,
+        @QueryParam("dn") String dn);
+
+    /*********************** Remote Service ***********************/
+
+    /**
+     * @see InfrastructureApi#listRemoteServices(DatacenterDto)
+     */
+    @GET
+    @Consumes(RemoteServicesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RemoteServicesDto> listRemoteServices(
+        @EndpointLink("remoteservices") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#createRemoteService(DatacenterDto, RemoteServiceDto)
+     */
+    @POST
+    @Produces(RemoteServiceDto.BASE_MEDIA_TYPE)
+    @Consumes(RemoteServiceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RemoteServiceDto> createRemoteService(
+        @EndpointLink("remoteservices") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(BindToXMLPayload.class) RemoteServiceDto remoteService);
+
+    /**
+     * @see InfrastructureApi#getRemoteService(DatacenterDto, RemoteServiceType)
+     */
+    @GET
+    @Consumes(RemoteServiceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<RemoteServiceDto> getRemoteService(
+        @EndpointLink("remoteservices") @BinderParam(BindToPath.class) final DatacenterDto datacenter,
+        @BinderParam(AppendRemoteServiceTypeToPath.class) final RemoteServiceType remoteServiceType);
+
+    /**
+     * @see InfrastructureApi#updateRemoteService(RemoteServiceDto)
+     */
+    @PUT
+    @Consumes(RemoteServiceDto.BASE_MEDIA_TYPE)
+    @Produces(RemoteServiceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<RemoteServiceDto> updateRemoteService(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) RemoteServiceDto remoteService);
+
+    /**
+     * @see InfrastructureApi#deleteRemoteService(RemoteServiceDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteRemoteService(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) RemoteServiceDto remoteService);
+
+    /**
+     * @see InfrastructureApi#isAvailable(RemoteServiceDto)
+     */
+    @GET
+    @ExceptionParser(ReturnFalseIfNotAvailable.class)
+    ListenableFuture<Boolean> isAvailable(
+        @EndpointLink("check") @BinderParam(BindToPath.class) RemoteServiceDto remoteService);
+
+    /*********************** Machine ***********************/
+
+    /**
+     * @see InfrastructureApi#listMachines(RackDto)
+     */
+    @GET
+    @Consumes(MachinesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<MachinesDto> listMachines(
+        @EndpointLink("machines") @BinderParam(BindToPath.class) RackDto rack);
+
+    /**
+     * @see InfrastructureApi#createMachine(RackDto, MachineDto)
+     */
+    @POST
+    @Produces(MachineDto.BASE_MEDIA_TYPE)
+    @Consumes(MachineDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<MachineDto> createMachine(
+        @EndpointLink("machines") @BinderParam(BindToPath.class) RackDto rack,
+        @BinderParam(BindToXMLPayload.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#getMachine(RackDto, Integer)
+     */
+    @GET
+    @Consumes(MachineDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<MachineDto> getMachine(
+        @EndpointLink("machines") @BinderParam(BindToPath.class) final RackDto rack,
+        @BinderParam(AppendToPath.class) Integer machineId);
+
+    /**
+     * @see InfrastructureApi#checkMachineState(MachineDto)
+     */
+    @GET
+    @Consumes(MachineStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<MachineStateDto> checkMachineState(
+        @EndpointLink("checkstate") @BinderParam(BindToPath.class) final MachineDto machine,
+        @QueryParam("sync") boolean sync);
+
+    /**
+     * @see InfrastructureApi#checkMachineIpmiState(MachineDto)
+     */
+    @GET
+    @Consumes(MachineIpmiStateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<MachineIpmiStateDto> checkMachineIpmiState(
+        @EndpointLink("checkipmistate") @BinderParam(BindToPath.class) final MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#updateMachine(MachineDto)
+     */
+    @PUT
+    @Produces(MachineDto.BASE_MEDIA_TYPE)
+    @Consumes(MachineDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<MachineDto> updateMachine(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#deleteMachine(MachineDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteMachine(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#reserveMachine(EnterpriseDto, MachineDto)
+     */
+    @POST
+    @Consumes(MachineDto.BASE_MEDIA_TYPE)
+    @Produces(MachineDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<MachineDto> reserveMachine(
+        @EndpointLink("reservedmachines") @BinderParam(BindToPath.class) EnterpriseDto enterprise,
+        @BinderParam(BindToXMLPayload.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#cancelReservation(EnterpriseDto, MachineDto)
+     */
+    @DELETE
+    ListenableFuture<Void> cancelReservation(
+        @EndpointLink("reservedmachines") @BinderParam(BindToPath.class) EnterpriseDto enterprise,
+        @BinderParam(AppendMachineIdToPath.class) MachineDto machine);
+
+    /*********************** Blade ***********************/
+
+    /**
+     * @see InfrastructureApi#powerOff(MachineDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    ListenableFuture<Void> powerOff(
+        @EndpointLink("poweroff") @BinderParam(BindToPath.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#powerOn(MachineDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    ListenableFuture<Void> powerOn(
+        @EndpointLink("poweron") @BinderParam(BindToPath.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#getLogicServer(MachineDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(LogicServerDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<LogicServerDto> getLogicServer(
+        @EndpointLink("logicserver") @BinderParam(BindToPath.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#ledOn(MachineDto)
+     */
+    @EnterpriseEdition
+    @POST
+    ListenableFuture<Void> ledOn(
+        @EndpointLink("ledon") @BinderParam(BindToPath.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#ledOff(MachineDto)
+     */
+    @EnterpriseEdition
+    @POST
+    ListenableFuture<Void> ledOff(
+        @EndpointLink("ledoff") @BinderParam(BindToPath.class) MachineDto machine);
+
+    /**
+     * @see InfrastructureApi#getLedLocator(MachineDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(BladeLocatorLedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<BladeLocatorLedDto> getLocatorLed(
+        @EndpointLink("led") @BinderParam(BindToPath.class) MachineDto machine);
+
+    /*********************** Storage Device ***********************/
+
+    /**
+     * @see InfrastructureApi#listVirtualMachinesByMachine(MachineDto)
+     */
+    @GET
+    @Consumes(VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachinesWithNodeExtendedDto> listVirtualMachinesByMachine(
+        @EndpointLink("virtualmachines") @BinderParam(BindToPath.class) MachineDto machine,
+        MachineOptions options);
+
+    /**
+     * @see InfrastructureApi#getVirtualMachine(MachineDto, Integer)
+     */
+    @GET
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    @Consumes(VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineWithNodeExtendedDto> getVirtualMachine(
+        @EndpointLink("virtualmachines") @BinderParam(BindToPath.class) MachineDto machine,
+        @BinderParam(AppendToPath.class) Integer virtualMachineId);
+
+    /*********************** Storage Device ***********************/
+
+    /**
+     * @see InfrastructureApi#listStorageDevices(DatacenterDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(StorageDevicesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<StorageDevicesDto> listStorageDevices(
+        @EndpointLink("devices") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#listSupportedStorageDevices(DatacenterDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(StorageDevicesMetadataDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<StorageDevicesMetadataDto> listSupportedStorageDevices(
+        @EndpointLink("devices") @BinderParam(BindSupportedDevicesLinkToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#getStorageDevice(DatacenterDto, Integer)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(StorageDeviceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<StorageDeviceDto> getStorageDevice(
+        @EndpointLink("devices") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(AppendToPath.class) Integer storageDeviceId);
+
+    /**
+     * @see InfrastructureApi#createStorageDevice(DatacenterDto, StorageDeviceDto)
+     */
+    @EnterpriseEdition
+    @POST
+    @Produces(StorageDeviceDto.BASE_MEDIA_TYPE)
+    @Consumes(StorageDeviceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<StorageDeviceDto> createStorageDevice(
+        @EndpointLink("devices") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(BindToXMLPayload.class) StorageDeviceDto storageDevice);
+
+    /**
+     * @see InfrastructureApi#deleteStorageDevice(StorageDeviceDto)
+     */
+    @EnterpriseEdition
+    @DELETE
+    ListenableFuture<Void> deleteStorageDevice(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) StorageDeviceDto storageDevice);
+
+    /**
+     * @see InfrastructureApi#updateStorageDevice(StorageDeviceDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    @Produces(StorageDeviceDto.BASE_MEDIA_TYPE)
+    @Consumes(StorageDeviceDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<StorageDeviceDto> updateStorageDevice(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) StorageDeviceDto storageDevice);
+
+    /*********************** Tier ***********************/
+
+    /**
+     * @see InfrastructureApi#listTiers(DatacenterDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(TiersDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<TiersDto> listTiers(
+        @EndpointLink("tiers") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#updateTier(TierDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    @Produces(TierDto.BASE_MEDIA_TYPE)
+    @Consumes(TierDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<TierDto> updateTier(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) TierDto tier);
+
+    /**
+     * @see InfrastructureApi#getTier(DatacenterDto, Integer)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(TierDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<TierDto> getTier(
+        @EndpointLink("tiers") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(AppendToPath.class) Integer tierId);
+
+    /*********************** Storage Pool ***********************/
+
+    /**
+     * @see InfrastructureApi#listStoragePools(StorageDeviceDto, StoragePoolOptions)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(StoragePoolsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<StoragePoolsDto> listStoragePools(
+        @EndpointLink("pools") @BinderParam(BindToPath.class) StorageDeviceDto storageDevice,
+        StoragePoolOptions options);
+
+    /**
+     * @see InfrastructureApi#listStoragePools(TierDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(StoragePoolsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<StoragePoolsDto> listStoragePools(
+        @EndpointLink("pools") @BinderParam(BindToPath.class) TierDto tier);
+
+    /**
+     * @see InfrastructureApi#createStoragePool(StorageDeviceDto, StoragePoolDto)
+     */
+    @EnterpriseEdition
+    @POST
+    @Consumes(StoragePoolDto.BASE_MEDIA_TYPE)
+    @Produces(StoragePoolDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<StoragePoolDto> createStoragePool(
+        @EndpointLink("pools") @BinderParam(BindToPath.class) StorageDeviceDto storageDevice,
+        @BinderParam(BindToXMLPayload.class) StoragePoolDto storagePool);
+
+    /**
+     * @see InfrastructureApi#updateStoragePool(StoragePoolDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    // For the most strangest reason in world, compiler does not accept
+    // constants StoragePoolDto.BASE_MEDIA_TYPE for this method.
+    @Consumes("application/vnd.abiquo.storagepool+xml")
+    @Produces("application/vnd.abiquo.storagepool+xml")
+    @JAXBResponseParser
+    ListenableFuture<StoragePoolDto> updateStoragePool(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) StoragePoolDto StoragePoolDto);
+
+    /**
+     * @see InfrastructureApi#deleteStoragePool(StoragePoolDto)
+     */
+    @EnterpriseEdition
+    @DELETE
+    ListenableFuture<Void> deleteStoragePool(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) StoragePoolDto storagePool);
+
+    /**
+     * @see InfrastructureApi#getStoragePool(StorageDeviceDto, String)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(StoragePoolDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<StoragePoolDto> getStoragePool(
+        @EndpointLink("pools") @BinderParam(BindToPath.class) final StorageDeviceDto storageDevice,
+        @BinderParam(AppendToPath.class) final String storagePoolId);
+
+    /**
+     * @see InfrastructureApi#refreshStoragePool(StoragePoolDto, StoragePoolOptions)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(StoragePoolDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<StoragePoolDto> refreshStoragePool(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) StoragePoolDto storagePool,
+        StoragePoolOptions options);
+
+    /*********************** Network ***********************/
+
+    /**
+     * @see InfrastructureApi#listNetworks(DatacenterDto)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(VLANNetworksDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworksDto> listNetworks(
+        @EndpointLink("network") @BinderParam(BindToPath.class) DatacenterDto datacenter);
+
+    /**
+     * @see InfrastructureApi#listNetwork(DatacenterDto, NetworkOptions)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(VLANNetworksDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworksDto> listNetworks(
+        @EndpointLink("network") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        NetworkOptions options);
+
+    /**
+     * @see InfrastructureApi#getNetwork(DatacenterDto, Integer)
+     */
+    @EnterpriseEdition
+    @GET
+    @Consumes(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<VLANNetworkDto> getNetwork(
+        @EndpointLink("network") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(AppendToPath.class) Integer networkId);
+
+    /**
+     * @see InfrastructureApi#createNetwork(DatacenterDto, VLANNetworkDto)
+     */
+    @EnterpriseEdition
+    @POST
+    @Produces(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @Consumes(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworkDto> createNetwork(
+        @EndpointLink("network") @BinderParam(BindToPath.class) DatacenterDto datacenter,
+        @BinderParam(BindToXMLPayload.class) VLANNetworkDto network);
+
+    /**
+     * @see InfrastructureApi#updateNetwork(VLANNetworkDto)
+     */
+    @EnterpriseEdition
+    @PUT
+    @Produces(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @Consumes(VLANNetworkDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VLANNetworkDto> updateNetwork(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) VLANNetworkDto network);
+
+    /**
+     * @see InfrastructureApi#deleteNetwork(VLANNetworkDto)
+     */
+    @EnterpriseEdition
+    @DELETE
+    ListenableFuture<Void> deleteNetwork(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) VLANNetworkDto network);
+
+    /**
+     * @see InfrastructureApi#checkTagAvailability(DatacenterDto, Integer)
+     */
+    @EnterpriseEdition
+    @GET
+    @Path("/datacenters/{datacenter}/network/action/checkavailability")
+    @Consumes(VlanTagAvailabilityDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VlanTagAvailabilityDto> checkTagAvailability(
+        @PathParam("datacenter") @ParamParser(ParseDatacenterId.class) DatacenterDto datacenter,
+        @QueryParam("tag") Integer tag);
+
+    /*********************** Public Network IPs ***********************/
+
+    /**
+     * @see InfrastructureApi#listPublicIps(VLANNetworkDto)
+     */
+    @GET
+    @Consumes(PublicIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PublicIpsDto> listPublicIps(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network);
+
+    /**
+     * @see InfrastructureApi#listPublicIps(VLANNetworkDto, IpOptions)
+     */
+    @GET
+    @Consumes(PublicIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PublicIpsDto> listPublicIps(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network,
+        IpOptions options);
+
+    /**
+     * @see InfrastructureApi#getPublicIp(VLANNetworkDto, Integer)
+     */
+    @GET
+    @Consumes(PublicIpDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<PublicIpDto> getPublicIp(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network,
+        @BinderParam(AppendToPath.class) Integer ipId);
+
+    /**
+     * @see InfrastructureApi#listExternalIps(VLANNetworkDto)
+     */
+    @GET
+    @Consumes(ExternalIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<ExternalIpsDto> listExternalIps(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network);
+
+    /**
+     * @see InfrastructureApi#listExternalIps(VLANNetworkDto, IpOptions)
+     */
+    @GET
+    @Consumes(ExternalIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<ExternalIpsDto> listExternalIps(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network,
+        IpOptions options);
+
+    /**
+     * @see InfrastructureApi#getExternalIp(VLANNetworkDto, Integer)
+     */
+    @GET
+    @Consumes(ExternalIpDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<ExternalIpDto> getExternalIp(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network,
+        @BinderParam(AppendToPath.class) Integer ipId);
+
+    /**
+     * @see InfrastructureApi#listUnmanagedIps(VLANNetworkDto)
+     */
+    @GET
+    @Consumes(UnmanagedIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UnmanagedIpsDto> listUnmanagedIps(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network);
+
+    /**
+     * @see InfrastructureApi#listUnmanagedIps(VLANNetworkDto, IpOptions)
+     */
+    @GET
+    @Consumes(UnmanagedIpsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UnmanagedIpsDto> listUnmanagedIps(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network,
+        IpOptions options);
+
+    /**
+     * @see InfrastructureApi#getUnmanagedIp(VLANNetworkDto, Integer)
+     */
+    @GET
+    @Consumes(UnmanagedIpDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<UnmanagedIpDto> getUnmanagedIp(
+        @EndpointLink("ips") @BinderParam(BindToPath.class) VLANNetworkDto network,
+        @BinderParam(AppendToPath.class) Integer ipId);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/PricingApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/PricingApi.java
new file mode 100644
index 0000000..989153b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/PricingApi.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.server.core.pricing.CurrenciesDto;
+import com.abiquo.server.core.pricing.CurrencyDto;
+
+/**
+ * Provides synchronous access to Abiquo Pricing API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see PricingAsyncApi
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface PricingApi
+{
+
+    /*********************** Currency ********************** */
+
+    /**
+     * List all currencies
+     * 
+     * @return The list of currencies
+     */
+    CurrenciesDto listCurrencies();
+
+    /**
+     * Get the given currency
+     * 
+     * @param currencyId The id of the currency
+     * @return The currency
+     */
+    CurrencyDto getCurrency(Integer currencyId);
+
+    /**
+     * Create a new currency
+     * 
+     * @param currency The currency to be created.
+     * @return The created currency.
+     */
+    CurrencyDto createCurrency(CurrencyDto currency);
+
+    /**
+     * Updates an existing currency
+     * 
+     * @param currency The new attributes for the currency
+     * @return The updated currency
+     */
+    CurrencyDto updateCurrency(final CurrencyDto currency);
+
+    /**
+     * Deletes an existing currency
+     * 
+     * @param currency The currency to delete
+     */
+    void deleteCurrency(final CurrencyDto currency);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/PricingAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/PricingAsyncApi.java
new file mode 100644
index 0000000..34dacbe
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/PricingAsyncApi.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.abiquo.binders.BindToXMLPayloadAndPath;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.abiquo.server.core.pricing.CurrenciesDto;
+import com.abiquo.server.core.pricing.CurrencyDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides synchronous access to Abiquo Pricing API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see PricingAsyncApi
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+@Path("/config")
+public interface PricingAsyncApi
+{
+    /*********************** Currency ********************** */
+
+    /**
+     * @see ConfigApi#listCurrencies()
+     */
+    @GET
+    @Path("/currencies")
+    @Consumes(CurrenciesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<CurrenciesDto> listCurrencies();
+
+    /**
+     * @see ConfigApi#getCurrency(Integer)
+     */
+    @GET
+    @Path("/currencies/{currency}")
+    @Consumes(CurrencyDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<CurrencyDto> getCurrency(@PathParam("currency") Integer currencyId);
+
+    /**
+     * @see ConfigApi#createCurrency(CurrencyDto)
+     */
+    @POST
+    @Path("/currencies")
+    @Produces(CurrencyDto.BASE_MEDIA_TYPE)
+    @Consumes(CurrencyDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<CurrencyDto> createCurrency(
+        @BinderParam(BindToXMLPayload.class) CurrencyDto currency);
+
+    /**
+     * @see ConfigApi#updateCurrency(CurrencyDto)
+     */
+    @PUT
+    @Produces(CurrencyDto.BASE_MEDIA_TYPE)
+    @Consumes(CurrencyDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<CurrencyDto> updateCurrency(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) CurrencyDto currency);
+
+    /**
+     * @see ConfigApi#deleteCurrency(CurrencyDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteCurrency(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) CurrencyDto currency);
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/TaskApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/TaskApi.java
new file mode 100644
index 0000000..92505dc
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/TaskApi.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.abiquo.server.core.task.TaskDto;
+import com.abiquo.server.core.task.TasksDto;
+
+/**
+ * Provides synchronous access to Abiquo Task API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see TaskAsyncApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface TaskApi
+{
+    /*********************** Task ***********************/
+
+    /**
+     * Get a task from its link.
+     * 
+     * @param link The link of the task.
+     * @return The task.
+     */
+    TaskDto getTask(final RESTLink link);
+
+    /**
+     * Get the list of tasks of the given object.
+     * 
+     * @param dto The object.
+     * @return The list of tasks for the given object.
+     */
+    <T extends SingleResourceTransportDto> TasksDto listTasks(T dto);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/TaskAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/TaskAsyncApi.java
new file mode 100644
index 0000000..1c1bd5b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/TaskAsyncApi.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+
+import org.jclouds.abiquo.binders.BindLinkToPath;
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.abiquo.functions.ReturnNullOn303;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.RequestFilters;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.abiquo.server.core.task.TaskDto;
+import com.abiquo.server.core.task.TasksDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Abiquo Task API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see TaskApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+public interface TaskAsyncApi
+{
+    /*********************** Task ***********************/
+
+    /**
+     * @see TaskApi#getTask(RESTLink)
+     */
+    @GET
+    @Consumes(TaskDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOn303.class)
+    ListenableFuture<TaskDto> getTask(@BinderParam(BindLinkToPath.class) RESTLink link);
+
+    /**
+     * @see TaskApi#listTasks(SingleResourceTransportDto)
+     */
+    @GET
+    @Consumes(TasksDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    <T extends SingleResourceTransportDto> ListenableFuture<TasksDto> listTasks(
+        @EndpointLink("tasks") @BinderParam(BindToPath.class) T dto);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/VirtualMachineTemplateApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/VirtualMachineTemplateApi.java
new file mode 100644
index 0000000..8fa30ea
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/VirtualMachineTemplateApi.java
@@ -0,0 +1,151 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.cloud.options.ConversionOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineTemplateOptions;
+import org.jclouds.concurrent.Timeout;
+
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.appslibrary.ConversionDto;
+import com.abiquo.server.core.appslibrary.ConversionsDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatePersistentDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+
+/**
+ * Provides synchronous access to Abiquo Apps library API.
+ * 
+ * @see API: <a href="http://community.abiquo.com/display/ABI20/API+Reference">
+ *      http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * @see VirtualMachineTemplateAsyncApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+public interface VirtualMachineTemplateApi
+{
+    /*********************** Virtual Machine Template ***********************/
+
+    /**
+     * List all virtual machine templates for an enterprise in a datacenter repository.
+     * 
+     * @param enterpriseId Id of the enterprise.
+     * @param datacenterRepositoryId Id of the datacenter repository contaning the templates.
+     * @return The list of virtual machine templates for the enterprise in the datacenter
+     *         repository.
+     */
+    VirtualMachineTemplatesDto listVirtualMachineTemplates(Integer enterpriseId,
+        Integer datacenterRepositoryId);
+
+    /**
+     * List all virtual machine templates for an enterprise in a datacenter repository.
+     * 
+     * @param enterpriseId Id of the enterprise.
+     * @param datacenterRepositoryId Id of the datacenter repository contaning the templates.
+     * @param options The options to query the virtual machine templates.
+     * @return The filtered list of virtual machine templates for the enterprise in the datacenter
+     *         repository.
+     */
+    VirtualMachineTemplatesDto listVirtualMachineTemplates(Integer enterpriseId,
+        Integer datacenterRepositoryId, VirtualMachineTemplateOptions options);
+
+    /**
+     * Get the given virtual machine template.
+     * 
+     * @param enterpriseId Id of the enterprise.
+     * @param datacenterRepositoryId Id of the datacenter repository contaning the templates.
+     * @param enterpriseId The id of the virtual machine template.
+     * @return The virtual machine template or <code>null</code> if it does not exist.
+     */
+    VirtualMachineTemplateDto getVirtualMachineTemplate(Integer entepriseId,
+        Integer datacenterRepositoryId, Integer virtualMachineTemplateId);
+
+    /**
+     * Updates an existing virtual machine template.
+     * 
+     * @param template The new attributes for the template.
+     * @return The updated template.
+     */
+    VirtualMachineTemplateDto updateVirtualMachineTemplate(VirtualMachineTemplateDto template);
+
+    /**
+     * Deletes an existing virtual machine template.
+     * 
+     * @param template The virtual machine template to delete.
+     */
+    void deleteVirtualMachineTemplate(VirtualMachineTemplateDto template);
+
+    /**
+     * Creates a persistent virtual machine template from other virtual machine template.
+     * 
+     * @param dcRepository The repository where the persistent virtual machine template will be
+     *            created.
+     * @param options The persistent options like name, volume/tier, virtual datacenter and original
+     *            template.
+     * @return Response message to the persistent request.
+     */
+    @Timeout(duration = 90, timeUnit = TimeUnit.SECONDS)
+    AcceptedRequestDto<String> createPersistentVirtualMachineTemplate(Integer enterpriseId,
+        Integer datacenterRepositoryId, VirtualMachineTemplatePersistentDto persistentOptions);
+
+    /**
+     * List all the conversions for a virtual machine template.
+     * 
+     * @param template, The virtual machine template of the conversions.
+     * @return The list of conversions for the virtual machine template.
+     */
+    ConversionsDto listConversions(VirtualMachineTemplateDto template);
+
+    /**
+     * List conversions for a virtual machine template.
+     * 
+     * @param template, The virtual machine template of the conversions
+     * @param options, Optionally filter compatible conversions with a provided hypervisor or with
+     *            the desired state.
+     * @return The list of conversions for the virtual machine template with the applied constrains.
+     */
+    ConversionsDto listConversions(VirtualMachineTemplateDto template, ConversionOptions options);
+
+    /**
+     * Get the conversions for a virtual machine template and the desired target format.
+     * 
+     * @param template, The virtual machine template of the conversion
+     * @param targetFormat The disk format type of the requested conversion
+     * @return The conversions for the virtual machine template with the desired target disk format
+     *         type.
+     */
+    ConversionDto getConversion(VirtualMachineTemplateDto template, DiskFormatType targetFormat);
+
+    /**
+     * Starts a V2V conversion of the current virtual machine template, or updates a failed
+     * conversion.
+     * 
+     * @param template The virtual machine template to convert
+     * @param targetFormat The requested target {@link DiskFormatType} of the conversion.
+     * @param conversion, the dto representing the conversion
+     * @return an accepted request with a link to track the progress of the conversion tasks.
+     */
+    AcceptedRequestDto<String> requestConversion(VirtualMachineTemplateDto template,
+        DiskFormatType targetFormat, ConversionDto conversion);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/VirtualMachineTemplateAsyncApi.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/VirtualMachineTemplateAsyncApi.java
new file mode 100644
index 0000000..ed3821b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/VirtualMachineTemplateAsyncApi.java
@@ -0,0 +1,184 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy 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.abiquo.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+import org.jclouds.abiquo.binders.AppendToPath;
+import org.jclouds.abiquo.binders.BindToPath;
+import org.jclouds.abiquo.binders.BindToXMLPayloadAndPath;
+import org.jclouds.abiquo.domain.cloud.options.ConversionOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineTemplateOptions;
+import org.jclouds.abiquo.functions.ReturnTaskReferenceOrNull;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.binders.BindToXMLPayload;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.appslibrary.ConversionDto;
+import com.abiquo.server.core.appslibrary.ConversionsDto;
+import com.abiquo.server.core.appslibrary.DatacenterRepositoryDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatePersistentDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Abiquo Abiquo Apps library API. * @see API: <a
+ * href="http://community.abiquo.com/display/ABI20/API+Reference">
+ * http://community.abiquo.com/display/ABI20/API+Reference</a>
+ * 
+ * @see VirtualMachineTemplateApi
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+@Path("/admin/enterprises")
+public interface VirtualMachineTemplateAsyncApi
+{
+    /*********************** Virtual Machine Template ***********************/
+
+    /**
+     * @see VirtualMachineTemplateApi#listVirtualMachineTemplates(Integer, Integer)
+     */
+    @GET
+    @Path("/{enterprise}/datacenterrepositories/{datacenterrepository}/virtualmachinetemplates")
+    @Consumes(VirtualMachineTemplatesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineTemplatesDto> listVirtualMachineTemplates(
+        @PathParam("enterprise") Integer enterpriseId,
+        @PathParam("datacenterrepository") Integer datacenterRepositoryId);
+
+    /**
+     * @see VirtualMachineTemplateApi#listVirtualMachineTemplates(Integer, Integer,
+     *      VirtualMachineTemplateOptions)
+     */
+    @GET
+    @Path("/{enterprise}/datacenterrepositories/{datacenterrepository}/virtualmachinetemplates")
+    @Consumes(VirtualMachineTemplatesDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineTemplatesDto> listVirtualMachineTemplates(
+        @PathParam("enterprise") Integer enterpriseId,
+        @PathParam("datacenterrepository") Integer datacenterRepositoryId,
+        VirtualMachineTemplateOptions options);
+
+    /**
+     * @see VirtualMachineTemplateApi#getVirtualMachineTemplate(Integer, Integer, Integer)
+     */
+    @GET
+    @Path("/{enterprise}/datacenterrepositories/{datacenterrepository}/virtualmachinetemplates/{virtualmachinetemplate}")
+    @Consumes(VirtualMachineTemplateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<VirtualMachineTemplateDto> getVirtualMachineTemplate(
+        @PathParam("enterprise") Integer enterpriseId,
+        @PathParam("datacenterrepository") Integer datacenterRepositoryId,
+        @PathParam("virtualmachinetemplate") Integer virtualMachineTemplateId);
+
+    /**
+     * @see VirtualMachineTemplateApi#updateVirtualMachineTemplate(VirtualMachineTemplateDto)
+     */
+    @PUT
+    @Produces(VirtualMachineTemplateDto.BASE_MEDIA_TYPE)
+    @Consumes(VirtualMachineTemplateDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<VirtualMachineTemplateDto> updateVirtualMachineTemplate(
+        @EndpointLink("edit") @BinderParam(BindToXMLPayloadAndPath.class) VirtualMachineTemplateDto template);
+
+    /**
+     * @see VirtualMachineTemplateApi#deleteVirtualMachineTemplate(VirtualMachineTemplateDto)
+     */
+    @DELETE
+    ListenableFuture<Void> deleteVirtualMachineTemplate(
+        @EndpointLink("edit") @BinderParam(BindToPath.class) VirtualMachineTemplateDto template);
+
+    /**
+     * @see VirtualMachineTemplateApi#createPersistentVirtualMachineTemplate(DatacenterRepositoryDto,
+     *      VirtualMachineTemplatePersistentDto)
+     */
+    @POST
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(VirtualMachineTemplatePersistentDto.BASE_MEDIA_TYPE)
+    @Path("/{enterprise}/datacenterrepositories/{datacenterrepository}/virtualmachinetemplates")
+    @JAXBResponseParser
+    ListenableFuture<AcceptedRequestDto<String>> createPersistentVirtualMachineTemplate(
+        @PathParam("enterprise") Integer enterpriseId,
+        @PathParam("datacenterrepository") Integer datacenterRepositoryId,
+        @BinderParam(BindToXMLPayload.class) VirtualMachineTemplatePersistentDto persistentOptions);
+
+    /*********************** Conversions ***********************/
+
+    /**
+     * @see VirtualMachineTemplateApi#listConversions(VirtualMachineTemplateDto)
+     */
+    @GET
+    @Consumes(ConversionsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<ConversionsDto> listConversions(
+        @EndpointLink("conversions") @BinderParam(BindToPath.class) VirtualMachineTemplateDto template);
+
+    /**
+     * @see VirtualMachineTemplateApi#listConversions(VirtualMachineTemplateDto, ConversionOptions)
+     */
+    @GET
+    @Consumes(ConversionsDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    ListenableFuture<ConversionsDto> listConversions(
+        @EndpointLink("conversions") @BinderParam(BindToPath.class) final VirtualMachineTemplateDto template,
+        ConversionOptions options);
+
+    /**
+     * @see VirtualMachineTemplateApi#getConversion(VirtualMachineTemplateDto, DiskFormatType)
+     */
+    @GET
+    @Consumes(ConversionDto.BASE_MEDIA_TYPE)
+    @JAXBResponseParser
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    ListenableFuture<ConversionDto> getConversion(
+        @EndpointLink("conversions") @BinderParam(BindToPath.class) final VirtualMachineTemplateDto template,
+        @BinderParam(AppendToPath.class) DiskFormatType targetFormat);
+
+    /**
+     * @see VirtualMachineTemplateApi#updateConversion(ConversinoDto)
+     */
+    @PUT
+    @ResponseParser(ReturnTaskReferenceOrNull.class)
+    @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+    @Produces(ConversionDto.BASE_MEDIA_TYPE)
+    ListenableFuture<AcceptedRequestDto<String>> requestConversion(
+        @EndpointLink("conversions") @BinderParam(BindToPath.class) final VirtualMachineTemplateDto template,
+        @BinderParam(AppendToPath.class) DiskFormatType targetFormat,
+        @BinderParam(BindToXMLPayload.class) ConversionDto conversion);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/AdministrationService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/AdministrationService.java
new file mode 100644
index 0000000..ab483b2
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/AdministrationService.java
@@ -0,0 +1,241 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features.services;
+
+import java.util.List;
+
+import org.jclouds.abiquo.domain.config.Category;
+import org.jclouds.abiquo.domain.config.License;
+import org.jclouds.abiquo.domain.config.Privilege;
+import org.jclouds.abiquo.domain.config.SystemProperty;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.EnterpriseProperties;
+import org.jclouds.abiquo.domain.enterprise.Role;
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+import org.jclouds.abiquo.internal.BaseAdministrationService;
+
+import com.google.common.base.Predicate;
+import com.google.inject.ImplementedBy;
+
+/**
+ * Provides high level Abiquo administration operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@ImplementedBy(BaseAdministrationService.class)
+public interface AdministrationService
+{
+    /*********************** Datacenter ***********************/
+
+    /**
+     * Get the list of all datacenters.
+     */
+    Iterable<Datacenter> listDatacenters();
+
+    /**
+     * Get the list of datacenters matching the given filter.
+     */
+    Iterable<Datacenter> listDatacenters(final Predicate<Datacenter> filter);
+
+    /**
+     * Get the first datacenter that matches the given filter or <code>null</code> if none is found.
+     */
+    Datacenter findDatacenter(final Predicate<Datacenter> filter);
+
+    /**
+     * Get the datacenter with the given id.
+     */
+    Datacenter getDatacenter(final Integer datacenterId);
+
+    /**
+     * Get the list of datacenters with the given ids.
+     */
+    Iterable<Datacenter> getDatacenters(final List<Integer> datacenterIds);
+
+    /*********************** Machine ***********************/
+
+    /**
+     * Get the list of all machines in the infrastructure.
+     */
+    public Iterable<Machine> listMachines();
+
+    /**
+     * Get the list of all machines in the infrastructure matching the given filter.
+     */
+    public Iterable<Machine> listMachines(Predicate<Machine> filter);
+
+    /**
+     * Get the first machine in the infrastructure that matches the given filter.
+     */
+    public Machine findMachine(Predicate<Machine> filter);
+
+    /*********************** Enterprise ***********************/
+
+    /**
+     * Get the list of all enterprises.
+     */
+    Iterable<Enterprise> listEnterprises();
+
+    /**
+     * Get the list of enterprises matching the given filter.
+     */
+    Iterable<Enterprise> listEnterprises(final Predicate<Enterprise> filter);
+
+    /**
+     * Get the first enterprises that matches the given filter or <code>null</code> if none is
+     * found.
+     */
+    Enterprise findEnterprise(final Predicate<Enterprise> filter);
+
+    /**
+     * Get the enterprise with the given id.
+     */
+    Enterprise getEnterprise(final Integer enterpriseId);
+
+    /*********************** Enterprise Properties ***********************/
+    /**
+     * Get the properties of an enterprise.
+     */
+    EnterpriseProperties getEnterpriseProperties(final Enterprise enterprise);
+
+    /*********************** Role ***********************/
+
+    /**
+     * Get the list of global roles.
+     */
+    Iterable<Role> listRoles();
+
+    /**
+     * Get the list of roles matching the given filter.
+     */
+    Iterable<Role> listRoles(final Predicate<Role> filter);
+
+    /**
+     * Get the first role that matches the given filter or <code>null</code> if none is found.
+     */
+    Role findRole(final Predicate<Role> filter);
+
+    /**
+     * Get the role with the given id.
+     */
+    Role getRole(final Integer roleId);
+
+    /*********************** Privilege ***********************/
+
+    /**
+     * Get the list of global privileges.
+     */
+    Iterable<Privilege> listPrivileges();
+
+    /**
+     * Get the list of privileges matching the given filter.
+     */
+    Iterable<Privilege> listPrivileges(final Predicate<Privilege> filter);
+
+    /**
+     * Get the first privilege that matches the given filter or <code>null</code> if none is found.
+     */
+    Privilege findPrivilege(final Predicate<Privilege> filter);
+
+    /*********************** User ***********************/
+
+    /**
+     * Get the current user.
+     */
+    User getCurrentUser();
+
+    /**
+     * Get the enterprise of the current user.
+     */
+    Enterprise getCurrentEnterprise();
+
+    /*********************** License ***********************/
+
+    /**
+     * Get the list of all licenses.
+     */
+    Iterable<License> listLicenses();
+
+    /**
+     * Get the list of all active/inactive licenses.
+     * 
+     * @param active Defines if searching for active (<code>true</code>) or inactive (
+     *            <code>false</code>) licenses.
+     */
+    Iterable<License> listLicenses(boolean active);
+
+    /**
+     * Get the list of licenses matching the given filter.
+     */
+    Iterable<License> listLicenses(final Predicate<License> filter);
+
+    /**
+     * Get the first license that matches the given filter or <code>null</code> if none is found.
+     */
+    License findLicense(final Predicate<License> filter);
+
+    /*********************** System Properties ***********************/
+
+    /**
+     * Get the list of system properties.
+     */
+    Iterable<SystemProperty> listSystemProperties();
+
+    /**
+     * Get the list of system properties matching the given filter.
+     */
+    Iterable<SystemProperty> listSystemProperties(final Predicate<SystemProperty> filter);
+
+    /**
+     * Get the first system property that matches the given filter or <code>null</code> if none is
+     * found.
+     */
+    SystemProperty findSystemProperty(final Predicate<SystemProperty> filter);
+
+    /**
+     * Get the system property with the give name or <code>null</code> if none is found.
+     */
+    SystemProperty getSystemProperty(String name);
+
+    /**
+     * Get the list of system properties with options.
+     */
+    Iterable<SystemProperty> listSystemProperties(String component);
+
+    /*********************** Category ***********************/
+
+    /**
+     * Get the list of categories.
+     */
+    Iterable<Category> listCategories();
+
+    /**
+     * Get the list of categories matching the given filter.
+     */
+    Iterable<Category> listCategories(final Predicate<Category> filter);
+
+    /**
+     * Get the first categories that matches the given filter or <code>null</code> if none is found.
+     */
+    Category findCategory(final Predicate<Category> filter);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/CloudService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/CloudService.java
new file mode 100644
index 0000000..18e597c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/CloudService.java
@@ -0,0 +1,111 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features.services;
+
+import java.util.List;
+
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.internal.BaseCloudService;
+
+import com.google.common.base.Predicate;
+import com.google.inject.ImplementedBy;
+
+/**
+ * Provides high level Abiquo cloud operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@ImplementedBy(BaseCloudService.class)
+public interface CloudService
+{
+    /*********************** Virtual Datacenter ***********************/
+
+    /**
+     * Get the list of all virtual datacenters.
+     */
+    Iterable<VirtualDatacenter> listVirtualDatacenters();
+
+    /**
+     * Get the list of all virtual datacenters for a pair enterprise-datacenter.
+     * 
+     * @param enterprise The given enterprise.
+     * @param datacenter The given datacenter.
+     */
+    Iterable<VirtualDatacenter> listVirtualDatacenters(final Enterprise enterprise);
+
+    /**
+     * Get the list of virtual datacenters matching the given filter.
+     */
+    Iterable<VirtualDatacenter> listVirtualDatacenters(final Predicate<VirtualDatacenter> filter);
+
+    /**
+     * Get the first virtual datacenter that matches the given filter or <code>null</code> if none
+     * is found.
+     */
+    VirtualDatacenter findVirtualDatacenter(final Predicate<VirtualDatacenter> filter);
+
+    /**
+     * Get the virtual datacenter with the given id.
+     */
+    VirtualDatacenter getVirtualDatacenter(final Integer virtualDatacenterId);
+
+    /**
+     * Get the list of virtual datacenter with the given ids.
+     */
+    Iterable<VirtualDatacenter> getVirtualDatacenters(final List<Integer> virtualDatacenterIds);
+
+    /*********************** Virtual Appliance ***********************/
+
+    /**
+     * Get the list of all virtual appliances.
+     */
+    Iterable<VirtualAppliance> listVirtualAppliances();
+
+    /**
+     * Get the list of the virtual appliances matching the given filter.
+     */
+    Iterable<VirtualAppliance> listVirtualAppliances(Predicate<VirtualAppliance> filter);
+
+    /**
+     * Get the first virtual appliance that matches the given filter.
+     */
+    VirtualAppliance findVirtualAppliance(Predicate<VirtualAppliance> filter);
+
+    /*********************** Virtual Machine ***********************/
+
+    /**
+     * Get the list of all virtual machines.
+     */
+    Iterable<VirtualMachine> listVirtualMachines();
+
+    /**
+     * Get the list of the virtual machines matching the given filter.
+     */
+    Iterable<VirtualMachine> listVirtualMachines(Predicate<VirtualMachine> filter);
+
+    /**
+     * Get the first virtual machine that matches the given filter.
+     */
+    VirtualMachine findVirtualMachine(Predicate<VirtualMachine> filter);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/EventService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/EventService.java
new file mode 100644
index 0000000..cf25fc6
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/EventService.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features.services;
+
+import org.jclouds.abiquo.domain.event.Event;
+import org.jclouds.abiquo.domain.event.options.EventOptions;
+import org.jclouds.abiquo.internal.BaseEventService;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * Provides high level Abiquo event operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Vivien Mahé
+ */
+@ImplementedBy(BaseEventService.class)
+public interface EventService
+{
+    /**
+     * Get the list of all events.
+     */
+    Iterable<Event> listEvents();
+
+    /**
+     * Get the list of all events using filters as query params.
+     */
+    Iterable<Event> listEvents(EventOptions options);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/MonitoringService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/MonitoringService.java
new file mode 100644
index 0000000..1706f39
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/MonitoringService.java
@@ -0,0 +1,137 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features.services;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.events.handlers.AbstractEventHandler;
+import org.jclouds.abiquo.internal.BaseMonitoringService;
+import org.jclouds.abiquo.monitor.AsyncTaskMonitor;
+import org.jclouds.abiquo.monitor.ConversionMonitor;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.abiquo.monitor.VirtualApplianceMonitor;
+import org.jclouds.abiquo.monitor.VirtualMachineMonitor;
+
+import com.google.common.base.Function;
+import com.google.inject.ImplementedBy;
+
+/**
+ * Utility service to monitor asynchronous operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@ImplementedBy(BaseMonitoringService.class)
+public interface MonitoringService
+{
+
+    /*************** Generic monitoring methods ***************/
+
+    /**
+     * Monitor the given objects using the given complete condition.
+     * 
+     * @param completeCondition The function that will be used to decide if the asynchronous
+     *            operations have finished.
+     * @param objects The objects to monitor.
+     */
+    public <T> void awaitCompletion(final Function<T, MonitorStatus> completeCondition,
+        final T... objects);
+
+    /**
+     * Monitor the given objects using the given complete condition.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param completeCondition The function that will be used to decide if the asynchronous
+     *            operations have finished.
+     * @param objects The objects to monitor.
+     */
+    public <T> void awaitCompletion(final Long maxWait, final TimeUnit timeUnit,
+        final Function<T, MonitorStatus> completeCondition, final T... objects);
+
+    /**
+     * Monitor the given objects using the given complete condition.
+     * 
+     * @param completeCondition The function that will be used to decide if the asynchronous
+     *            operations have finished.
+     * @param objects The objects to monitor.
+     */
+    public <T> void monitor(final Function<T, MonitorStatus> completeCondition, final T... objects);
+
+    /**
+     * Monitor the given objects using the given complete condition.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param completeCondition The function that will be used to decide if the asynchronous
+     *            operations have finished.
+     * @param objects The objects to monitor.
+     */
+    public <T> void monitor(final Long maxWait, final TimeUnit timeUnit,
+        final Function<T, MonitorStatus> completeCondition, final T... objects);
+
+    /*************** Handler registration methods ***************/
+
+    /**
+     * Registers the given event handler.
+     * 
+     * @param <T> The type of event handler to register.
+     * @param handler The event handler to register.
+     */
+    public <T extends AbstractEventHandler< ? >> void register(T handler);
+
+    /**
+     * Unregisters the given event handler.
+     * 
+     * @param <T> The type of event handler to unregister.
+     * @param handler The event handler to unregister.
+     */
+    public <T extends AbstractEventHandler< ? >> void unregister(T handler);
+
+    /*************** Delegating monitors ***************/
+
+    /**
+     * Gets the virtual machine monitor service.
+     * 
+     * @return The virtual machine monitor service.
+     */
+    public VirtualMachineMonitor getVirtualMachineMonitor();
+
+    /**
+     * Gets the virtual appliance monitor service.
+     * 
+     * @return The virtual appliance monitor service.
+     */
+    public VirtualApplianceMonitor getVirtualApplianceMonitor();
+
+    /**
+     * Gets the asynchronous task monitor service.
+     * 
+     * @return The asynchronous task monitor service.
+     */
+    public AsyncTaskMonitor getAsyncTaskMonitor();
+
+    /**
+     * Gets the conversion monitor service.
+     * 
+     * @return The conversion monitor service.
+     */
+    public ConversionMonitor getConversionMonitor();
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/PricingService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/PricingService.java
new file mode 100644
index 0000000..4422007
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/PricingService.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features.services;
+
+import org.jclouds.abiquo.domain.config.Currency;
+import org.jclouds.abiquo.internal.BasePricingService;
+
+import com.google.common.base.Predicate;
+import com.google.inject.ImplementedBy;
+
+/**
+ * Provides high level Abiquo administration operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ */
+@ImplementedBy(BasePricingService.class)
+public interface PricingService
+{
+
+    /*********************** Currency ***********************/
+
+    /**
+     * Get the list of currencies.
+     */
+    Iterable<Currency> listCurrencies();
+
+    /**
+     * Get the list of currencies matching the given filter.
+     */
+    Iterable<Currency> listCurrencies(final Predicate<Currency> filter);
+
+    /**
+     * Get the first currencies that matches the given filter or <code>null</code> if none is found.
+     */
+    Currency findCurrency(final Predicate<Currency> filter);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/SearchService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/SearchService.java
new file mode 100644
index 0000000..33b6df4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/features/services/SearchService.java
@@ -0,0 +1,143 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features.services;
+
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.Volume;
+import org.jclouds.abiquo.domain.cloud.options.VolumeOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.options.EnterpriseOptions;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.LogicServer;
+import org.jclouds.abiquo.domain.infrastructure.ManagedRack;
+import org.jclouds.abiquo.domain.infrastructure.StorageDevice;
+import org.jclouds.abiquo.domain.infrastructure.StoragePool;
+import org.jclouds.abiquo.domain.infrastructure.options.StoragePoolOptions;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PrivateNetwork;
+import org.jclouds.abiquo.domain.network.PublicIp;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.domain.options.search.FilterOptions;
+import org.jclouds.abiquo.internal.BaseSearchService;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * Provides high level Abiquo search, filter and pagination operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@ImplementedBy(BaseSearchService.class)
+public interface SearchService
+{
+    /*********************** Enterprise ***********************/
+
+    /**
+     * Get the list of filtered enterprises.
+     * 
+     * @param options The set of filtering and pagination options of the search.
+     */
+    Iterable<Enterprise> searchEnterprises(final EnterpriseOptions options);
+
+    /**
+     * Get the list of filtered enterprises for a datacenter.
+     * 
+     * @param datacenter The given datacenter.
+     * @param options The set of filtering and pagination options of the search.
+     * @see API: <a href=
+     *      "http://community.abiquo.com/display/ABI20/Datacenter+Resource#DatacenterResource-Retrievealistofenterprisesusingdatacenter"
+     *      > http://community.abiquo.com/display/ABI20/Datacenter+Resource#DatacenterResource-
+     *      Retrievealistofenterprisesusingdatacenter</a>
+     */
+    Iterable<Enterprise> searchEnterprisesUsingDatacenter(final Datacenter datacenter,
+        final EnterpriseOptions options);
+
+    /*********************** Volume ***********************/
+
+    /**
+     * Get the list of filtered volumes for a virtual datacenter.
+     * 
+     * @param virtualDatacenter The given virtual datacenter.
+     * @param options The set of filtering and pagination options of the search.
+     */
+    Iterable<Volume> searchVolumes(final VirtualDatacenter virtualDatacenter,
+        final VolumeOptions options);
+
+    /*********************** Storage Pool ***********************/
+
+    /**
+     * Get the list of filtered storage pools for a storage device.
+     * 
+     * @param device The given storage device.
+     * @param options The set of filtering and pagination options of the search.
+     */
+    Iterable<StoragePool> searchStoragePools(final StorageDevice device,
+        final StoragePoolOptions options);
+
+    /*********************** Private IPs ***********************/
+
+    /**
+     * Get the list of filtered ips for a private network.
+     * 
+     * @param network The given private network.
+     * @param options The set of filtering and pagination options of the search.
+     */
+    Iterable<PrivateIp> searchPrivateIps(final PrivateNetwork network, final IpOptions options);
+
+    /*********************** Public IPs ***********************/
+
+    /**
+     * Get the list of filtered public ips to purchase by a virtual datacenter.
+     * 
+     * @param virtualDatacenter The given virtual datacenter.
+     * @param options The set of filtering and pagination options of the search.
+     */
+    Iterable<PublicIp> searchPublicIpsToPurchase(final VirtualDatacenter virtualDatacenter,
+        final IpOptions options);
+
+    /**
+     * Get the list of filtered purchased public ips by a virtual datacenter.
+     * 
+     * @param virtualDatacenter The given virtual datacenter.
+     * @param options The set of filtering and pagination options of the search.
+     */
+    Iterable<PublicIp> searchPurchasedPublicIps(final VirtualDatacenter virtualDatacenter,
+        final IpOptions options);
+
+    /*********************** Logic Server ***********************/
+
+    /**
+     * Get the list of service profiles for managed rack.
+     * 
+     * @param managedRack The given rack.
+     * @param options The set of filtering and pagination options of the search.
+     */
+    Iterable<LogicServer> searchServiceProfiles(final ManagedRack rack, final FilterOptions options);
+
+    /**
+     * Get the list of service profile templates for managed rack.
+     * 
+     * @param managedRack The given rack.
+     * @param options The set of filtering and pagination options of the search.
+     */
+    Iterable<LogicServer> searchServiceProfileTemplates(final ManagedRack rack,
+        final FilterOptions options);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/AppendApiVersionToAbiquoMimeType.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/AppendApiVersionToAbiquoMimeType.java
new file mode 100644
index 0000000..e611341
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/AppendApiVersionToAbiquoMimeType.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.rest.annotations.ApiVersion;
+
+import com.google.common.base.Function;
+
+/**
+ * Appends the Api version to the given mime type.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AppendApiVersionToAbiquoMimeType implements Function<String, String>
+{
+    /** The prefix for Abiquo custom media types. */
+    private static final String ABIQUO_MIME_TYPE_PREFIX = "application/vnd.abiquo.";
+
+    /** The version to append to media types without version. */
+    protected String apiVersion;
+
+    @Inject
+    public AppendApiVersionToAbiquoMimeType(@ApiVersion final String apiVersion)
+    {
+        super();
+        this.apiVersion = checkNotNull(apiVersion, "apiVersion");
+    }
+
+    @Override
+    public String apply(final String input)
+    {
+        MediaType mediaType = MediaType.valueOf(checkNotNull(input, "input"));
+        if (isAbiquoMimeType(input) && !mediaType.getParameters().containsKey("version"))
+        {
+            return mediaType.toString() + ";version=" + apiVersion;
+        }
+        else
+        {
+            return mediaType.toString();
+        }
+    }
+
+    private static boolean isAbiquoMimeType(final String mimeType)
+    {
+        return mimeType.startsWith(ABIQUO_MIME_TYPE_PREFIX);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ParseErrors.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ParseErrors.java
new file mode 100644
index 0000000..52a31ff
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ParseErrors.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.transport.error.ErrorsDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Parses a errors object.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ParseErrors extends ParseXMLWithJAXB<ErrorsDto>
+{
+    @Inject
+    public ParseErrors(final XMLParser xml, final TypeLiteral<ErrorsDto> type)
+    {
+        super(xml, type);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnAbiquoExceptionOnNotFoundOr4xx.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnAbiquoExceptionOnNotFoundOr4xx.java
new file mode 100644
index 0000000..c755d03
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnAbiquoExceptionOnNotFoundOr4xx.java
@@ -0,0 +1,63 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+/**
+ * Return an Abiquo Exception on not found errors.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ReturnAbiquoExceptionOnNotFoundOr4xx implements Function<Exception, Object>
+{
+    @Override
+    public Object apply(final Exception from)
+    {
+        Throwable exception =
+            Iterables.find(Throwables.getCausalChain(from), isNotFoundAndHasAbiquoException(from),
+                null);
+
+        throw Throwables.propagate(exception == null ? from : (AbiquoException) exception
+            .getCause());
+    }
+
+    private static Predicate<Throwable> isNotFoundAndHasAbiquoException(final Throwable exception)
+    {
+        return new Predicate<Throwable>()
+        {
+            @Override
+            public boolean apply(final Throwable input)
+            {
+                return input instanceof ResourceNotFoundException
+                    && input.getCause() instanceof AbiquoException;
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnFalseIfNotAvailable.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnFalseIfNotAvailable.java
new file mode 100644
index 0000000..b1babe8
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnFalseIfNotAvailable.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+/**
+ * Return false on service error exceptions.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ReturnFalseIfNotAvailable implements Function<Exception, Object>
+{
+    @Override
+    public Object apply(final Exception from)
+    {
+        Throwable exception =
+            Iterables.find(Throwables.getCausalChain(from), isNotAvailableException(from), null);
+
+        if (exception != null)
+        {
+            if (exception instanceof HttpResponseException)
+            {
+                HttpResponseException responseException = (HttpResponseException) exception;
+                HttpResponse response = responseException.getResponse();
+
+                if (response != null && response.getStatusCode() >= 500
+                    && response.getStatusCode() < 600)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                // Will enter here when exception is a ResourceNotFoundException
+                return false;
+            }
+        }
+
+        throw Throwables.propagate(from);
+    }
+
+    private static Predicate<Throwable> isNotAvailableException(final Throwable exception)
+    {
+        return new Predicate<Throwable>()
+        {
+            @Override
+            public boolean apply(final Throwable input)
+            {
+                boolean notAvailable =
+                    input instanceof HttpResponseException
+                        && ((HttpResponseException) input).getResponse() != null;
+
+                notAvailable |= input instanceof ResourceNotFoundException;
+
+                return notAvailable;
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnFalseOn5xx.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnFalseOn5xx.java
new file mode 100644
index 0000000..150b8c4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnFalseOn5xx.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+/**
+ * Return false on service error exceptions.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ReturnFalseOn5xx implements Function<Exception, Object>
+{
+    @Override
+    public Object apply(final Exception from)
+    {
+        Throwable exception =
+            Iterables.find(Throwables.getCausalChain(from), hasResponse(from), null);
+
+        if (exception != null)
+        {
+            HttpResponseException responseException = (HttpResponseException) exception;
+            HttpResponse response = responseException.getResponse();
+
+            if (response != null && response.getStatusCode() >= 500
+                && response.getStatusCode() < 600)
+            {
+                return false;
+            }
+        }
+
+        throw Throwables.propagate(from);
+    }
+
+    private static Predicate<Throwable> hasResponse(final Throwable exception)
+    {
+        return new Predicate<Throwable>()
+        {
+            @Override
+            public boolean apply(final Throwable input)
+            {
+                return input instanceof HttpResponseException
+                    && ((HttpResponseException) input).getResponse() != null;
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnMovedResource.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnMovedResource.java
new file mode 100644
index 0000000..ec2bc24
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnMovedResource.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+/**
+ * Return false on service error exceptions.
+ * 
+ * @author Ignasi Barrera
+ */
+public abstract class ReturnMovedResource<T> implements Function<Exception, T>
+{
+
+    @Override
+    public T apply(final Exception from)
+    {
+        Throwable exception =
+            Iterables.find(Throwables.getCausalChain(from), isMovedException(from), null);
+
+        if (exception != null)
+        {
+            HttpResponseException responseException = (HttpResponseException) exception;
+            HttpResponse response = responseException.getResponse();
+
+            return getMovedEntity(response);
+        }
+
+        throw Throwables.propagate(from);
+    }
+
+    protected abstract T getMovedEntity(HttpResponse response);
+
+    private static Predicate<Throwable> isMovedException(final Throwable exception)
+    {
+        return new Predicate<Throwable>()
+        {
+            @Override
+            public boolean apply(final Throwable input)
+            {
+                if (input instanceof HttpResponseException)
+                {
+                    HttpResponse response = ((HttpResponseException) input).getResponse();
+                    return response != null
+                        && response.getStatusCode() == Status.MOVED_PERMANENTLY.getStatusCode();
+                }
+
+                return false;
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnNullOn303.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnNullOn303.java
new file mode 100644
index 0000000..630d6f3
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnNullOn303.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import javax.inject.Singleton;
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+
+/**
+ * Return <code>null</code> on 303 response codes when requesting a task.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ReturnNullOn303 implements Function<Exception, Object>
+{
+    @Override
+    public Object apply(final Exception from)
+    {
+        Throwable exception =
+            Iterables.find(Throwables.getCausalChain(from), hasResponse(from), null);
+
+        if (exception != null)
+        {
+            HttpResponseException responseException = (HttpResponseException) exception;
+            HttpResponse response = responseException.getResponse();
+
+            if (response != null && response.getStatusCode() == Status.SEE_OTHER.getStatusCode())
+            {
+                return null;
+            }
+        }
+
+        throw Throwables.propagate(from);
+    }
+
+    private static Predicate<Throwable> hasResponse(final Throwable exception)
+    {
+        return new Predicate<Throwable>()
+        {
+            @Override
+            public boolean apply(final Throwable input)
+            {
+                return input instanceof HttpResponseException
+                    && ((HttpResponseException) input).getResponse() != null;
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnTaskReferenceOrNull.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnTaskReferenceOrNull.java
new file mode 100644
index 0000000..ee5c8bf
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/ReturnTaskReferenceOrNull.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import static org.jclouds.http.HttpUtils.releasePayload;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Return an {@link AcceptedRequestDto} representing the asynchronous task or <code>null</code> if
+ * the operation completed synchronously.
+ * <p>
+ * Operations that generate asynchronous tasks will return one of the following:
+ * <ul>
+ * <li>204 if the operation completed synchronously</li>
+ * <li>202 with the asynchronous task reference in the body if the operation has been submitted and
+ * will be executed asynchronously</li>
+ * </ul>
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ReturnTaskReferenceOrNull extends ParseXMLWithJAXB<AcceptedRequestDto<String>>
+{
+    @Inject
+    public ReturnTaskReferenceOrNull(final XMLParser xml,
+        final TypeLiteral<AcceptedRequestDto<String>> type)
+    {
+        super(xml, type);
+    }
+
+    @Override
+    public AcceptedRequestDto<String> apply(final HttpResponse from)
+    {
+        if (from.getStatusCode() == Status.NO_CONTENT.getStatusCode())
+        {
+            releasePayload(from);
+            return null;
+        }
+        else
+        {
+            return super.apply(from);
+        }
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/cloud/ReturnMoveVolumeReference.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/cloud/ReturnMoveVolumeReference.java
new file mode 100644
index 0000000..41fb84b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/cloud/ReturnMoveVolumeReference.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.cloud;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.server.core.infrastructure.storage.MovedVolumeDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Return an {@link MovedVolumeDto} representing the reference to a moved resource.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ReturnMoveVolumeReference extends ParseXMLWithJAXB<MovedVolumeDto>
+{
+    @Inject
+    public ReturnMoveVolumeReference(final XMLParser xml, final TypeLiteral<MovedVolumeDto> type)
+    {
+        super(xml, type);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/cloud/ReturnMovedVolume.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/cloud/ReturnMovedVolume.java
new file mode 100644
index 0000000..78ed3f1
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/cloud/ReturnMovedVolume.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.cloud;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.functions.ReturnMovedResource;
+import org.jclouds.http.HttpResponse;
+
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+
+/**
+ * Return false on service error exceptions.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ReturnMovedVolume extends ReturnMovedResource<VolumeManagementDto>
+{
+    private ReturnMoveVolumeReference parser;
+
+    @Inject
+    public ReturnMovedVolume(final ReturnMoveVolumeReference parser)
+    {
+        super();
+        this.parser = parser;
+    }
+
+    @Override
+    protected VolumeManagementDto getMovedEntity(final HttpResponse response)
+    {
+        return parser.apply(response).getVolume();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/enterprise/ParseEnterpriseId.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/enterprise/ParseEnterpriseId.java
new file mode 100644
index 0000000..ca00e58
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/enterprise/ParseEnterpriseId.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.enterprise;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.google.common.base.Function;
+
+/**
+ * Parses a {@link EnterpriseDto} object to extract its id.
+ * 
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ParseEnterpriseId implements Function<Object, String>
+{
+    @Override
+    public String apply(final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof EnterpriseDto,
+            "This parser is only valid for EnterpriseDto objects");
+
+        return ((EnterpriseDto) input).getId().toString();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseDatacenterId.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseDatacenterId.java
new file mode 100644
index 0000000..4235755
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseDatacenterId.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.infrastructure;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.google.common.base.Function;
+
+/**
+ * Parses a {@link DatacenterDto} object to extract its id.
+ * 
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ParseDatacenterId implements Function<Object, String>
+{
+    @Override
+    public String apply(final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof DatacenterDto,
+            "This parser is only valid for DatacenterDto objects");
+
+        return ((DatacenterDto) input).getId().toString();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseMachineId.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseMachineId.java
new file mode 100644
index 0000000..54d1ef6
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseMachineId.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.infrastructure;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.google.common.base.Function;
+
+/**
+ * Parses a {@link MachineDto} object to extract its id.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ParseMachineId implements Function<Object, String>
+{
+    @Override
+    public String apply(final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof MachineDto,
+            "This parser is only valid for MachineDto objects");
+
+        return ((MachineDto) input).getId().toString();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseRemoteServiceType.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseRemoteServiceType.java
new file mode 100644
index 0000000..c30891c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/functions/infrastructure/ParseRemoteServiceType.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.infrastructure;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Singleton;
+
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.google.common.base.Function;
+
+/**
+ * Parses a {@link ParseRemoteServiceType} object to extract its type in the format that the API
+ * expects it.
+ * 
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ParseRemoteServiceType implements Function<Object, String>
+{
+    @Override
+    public String apply(final Object input)
+    {
+        checkArgument(checkNotNull(input, "input") instanceof RemoteServiceType,
+            "This parser is only valid for RemoteServiceType objects");
+
+        return ((RemoteServiceType) input).name().replaceAll("_", "").toLowerCase();
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/handlers/AbiquoErrorHandler.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/handlers/AbiquoErrorHandler.java
new file mode 100644
index 0000000..22aa746
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/handlers/AbiquoErrorHandler.java
@@ -0,0 +1,137 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.handlers;
+
+import static javax.ws.rs.core.Response.Status.fromStatusCode;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.functions.ParseErrors;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.abiquo.model.transport.error.ErrorsDto;
+import com.google.common.io.Closeables;
+
+/**
+ * Parse Abiquo API errors and set the appropriate exception.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AbiquoErrorHandler implements HttpErrorHandler
+{
+    /** The error parser. */
+    private ParseErrors errorParser;
+
+    @Inject
+    AbiquoErrorHandler(final ParseErrors errorParser)
+    {
+        super();
+        this.errorParser = errorParser;
+    }
+
+    @Override
+    public void handleError(final HttpCommand command, final HttpResponse response)
+    {
+        Exception exception = null;
+        String defaultMessage =
+            String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+                response.getStatusLine());
+
+        try
+        {
+            switch (response.getStatusCode())
+            {
+                case 401:
+                case 403:
+                    // Autorization exceptions do not return an errors DTO, so we encapsulate a
+                    // generic exception
+                    exception =
+                        new AuthorizationException(defaultMessage,
+                            new HttpResponseException(command, response, defaultMessage));
+                    break;
+                case 404:
+                    exception =
+                        new ResourceNotFoundException(defaultMessage, getExceptionToPropagate(
+                            command, response, defaultMessage));
+                    break;
+                case 301:
+                    // Moved resources in Abiquo should be handled with the ReturnMovedResource
+                    // exception parser to return the moved entity.
+                    exception = new HttpResponseException(command, response, defaultMessage);
+                    break;
+                default:
+                    exception = getExceptionToPropagate(command, response, defaultMessage);
+                    break;
+            }
+        }
+        finally
+        {
+            if (response.getPayload() != null)
+            {
+                Closeables.closeQuietly(response.getPayload().getInput());
+            }
+            command.setException(exception);
+        }
+    }
+
+    private Exception getExceptionToPropagate(final HttpCommand command,
+        final HttpResponse response, final String defaultMessage)
+    {
+        Exception exception = null;
+
+        if (hasPayload(response))
+        {
+            try
+            {
+                ErrorsDto errors = errorParser.apply(response);
+                exception = new AbiquoException(fromStatusCode(response.getStatusCode()), errors);
+            }
+            catch (Exception ex)
+            {
+                // If it is not an Abiquo Exception (can not be unmarshalled), propagate a standard
+                // HttpResponseException
+                exception = new HttpResponseException(command, response, defaultMessage);
+            }
+        }
+        else
+        {
+            // If it is not an Abiquo Exception (there is not an errors xml in the payload)
+            // propagate a standard HttpResponseException
+            exception = new HttpResponseException(command, response, defaultMessage);
+        }
+
+        return exception;
+    }
+
+    private static boolean hasPayload(final HttpResponse response)
+    {
+        return response.getPayload() != null && response.getPayload().getContentMetadata() != null
+            && response.getPayload().getContentMetadata().getContentLength() != null
+            && response.getPayload().getContentMetadata().getContentLength() > 0L;
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/http/filters/AbiquoAuthentication.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/http/filters/AbiquoAuthentication.java
new file mode 100644
index 0000000..f3a462e
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/http/filters/AbiquoAuthentication.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.http.filters;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.abiquo.config.AbiquoProperties.CREDENTIAL_IS_TOKEN;
+
+import java.io.UnsupportedEncodingException;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.ws.rs.core.HttpHeaders;
+
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+import org.jclouds.rest.annotations.Credential;
+import org.jclouds.rest.annotations.Identity;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Authenticates using Basic Authentication or a generated token from previous API sessions.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AbiquoAuthentication implements HttpRequestFilter
+{
+    /** The name of the authentication token. */
+    public static final String AUTH_TOKEN_NAME = "auth";
+
+    protected String identity;
+
+    protected String credential;
+
+    protected boolean credentialIsToken;
+
+    @Inject
+    public AbiquoAuthentication(@Identity final String identity,
+        @Credential final String credential,
+        @Named(CREDENTIAL_IS_TOKEN) final String credentialIsToken)
+    {
+        this.identity = checkNotNull(identity, "identity");
+        this.credential = checkNotNull(credential, "credential");
+        this.credentialIsToken = Boolean.valueOf(credentialIsToken);
+    }
+
+    @Override
+    public HttpRequest filter(final HttpRequest request) throws HttpException
+    {
+        try
+        {
+            String header =
+                credentialIsToken ? tokenAuth(credential) : basicAuth(identity, credential);
+            return request
+                .toBuilder()
+                .replaceHeader(credentialIsToken ? HttpHeaders.COOKIE : HttpHeaders.AUTHORIZATION,
+                    header).build();
+        }
+        catch (UnsupportedEncodingException ex)
+        {
+            throw new HttpException(ex);
+        }
+    }
+
+    @VisibleForTesting
+    static String basicAuth(final String user, final String password)
+        throws UnsupportedEncodingException
+    {
+        return "Basic "
+            + CryptoStreams.base64(String.format("%s:%s", checkNotNull(user, "user"),
+                checkNotNull(password, "password")).getBytes("UTF-8"));
+    }
+
+    @VisibleForTesting
+    static String tokenAuth(final String token)
+    {
+        return AUTH_TOKEN_NAME + "=" + checkNotNull(token, "token");
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/http/filters/AppendApiVersionToMediaType.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/http/filters/AppendApiVersionToMediaType.java
new file mode 100644
index 0000000..6a6ba06
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/http/filters/AppendApiVersionToMediaType.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.http.filters;
+
+import java.util.Collection;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.functions.AppendApiVersionToAbiquoMimeType;
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Iterables;
+import com.google.common.net.HttpHeaders;
+
+/**
+ * Appends the api version to the Abiquo mime types to ensure the input and output of api calls will
+ * be in the desired format.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AppendApiVersionToMediaType implements HttpRequestFilter
+{
+    /** The function used to append the version to media types. */
+    private AppendApiVersionToAbiquoMimeType versionAppender;
+
+    @Inject
+    public AppendApiVersionToMediaType(final AppendApiVersionToAbiquoMimeType versionAppender)
+    {
+        super();
+        this.versionAppender = versionAppender;
+    }
+
+    @Override
+    public HttpRequest filter(final HttpRequest request) throws HttpException
+    {
+        HttpRequest requestWithVersionInMediaTypes = appendVersionToNonPayloadHeaders(request);
+        return appendVersionToPayloadHeaders(requestWithVersionInMediaTypes);
+    }
+
+    @VisibleForTesting
+    HttpRequest appendVersionToNonPayloadHeaders(final HttpRequest request)
+    {
+        Collection<String> accept = request.getHeaders().get(HttpHeaders.ACCEPT);
+        return accept.isEmpty() ? request : request
+            .toBuilder()
+            .replaceHeader(HttpHeaders.ACCEPT,
+                Iterables.toArray(Iterables.transform(accept, versionAppender), String.class))
+            .build();
+    }
+
+    @VisibleForTesting
+    HttpRequest appendVersionToPayloadHeaders(final HttpRequest request)
+    {
+        if (request.getPayload() != null)
+        {
+            String contentTypeWithVersion =
+                versionAppender.apply(request.getPayload().getContentMetadata().getContentType());
+            request.getPayload().getContentMetadata().setContentType(contentTypeWithVersion);
+        }
+
+        return request;
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/AbiquoContextImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/AbiquoContextImpl.java
new file mode 100644
index 0000000..837bb84
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/AbiquoContextImpl.java
@@ -0,0 +1,125 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.Context;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoContext;
+import org.jclouds.abiquo.features.services.AdministrationService;
+import org.jclouds.abiquo.features.services.CloudService;
+import org.jclouds.abiquo.features.services.EventService;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.features.services.PricingService;
+import org.jclouds.abiquo.features.services.SearchService;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.Utils;
+import org.jclouds.compute.internal.ComputeServiceContextImpl;
+import org.jclouds.location.Provider;
+import org.jclouds.rest.RestContext;
+import org.jclouds.rest.internal.RestContextImpl;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Abiquo {@link RestContextImpl} implementation to expose high level Abiquo functionalities.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AbiquoContextImpl extends ComputeServiceContextImpl implements AbiquoContext
+{
+    private final AdministrationService administrationService;
+
+    private final CloudService cloudService;
+
+    private final SearchService searchService;
+
+    private final MonitoringService monitoringService;
+
+    private final EventService eventService;
+
+    private final PricingService pricingService;
+
+    @Inject
+    public AbiquoContextImpl(@Provider final Context wrapped,
+        @Provider final TypeToken< ? extends Context> wrappedType,
+        final ComputeService computeService, final Utils utils,
+        final RestContext<AbiquoApi, AbiquoAsyncApi> providerSpecificContext,
+        final AdministrationService administrationService, final CloudService cloudService,
+        final SearchService searchService, final MonitoringService monitoringService,
+        final EventService eventService, final PricingService pricingService)
+    {
+        super(wrapped, wrappedType, computeService, utils);
+        this.administrationService = checkNotNull(administrationService, "administrationService");
+        this.cloudService = checkNotNull(cloudService, "cloudService");
+        this.searchService = checkNotNull(searchService, "searchService");
+        this.monitoringService = checkNotNull(monitoringService, "monitoringService");
+        this.eventService = checkNotNull(eventService, "eventService");
+        this.pricingService = checkNotNull(pricingService, "pricingService");
+    }
+
+    @Override
+    public RestContext<AbiquoApi, AbiquoAsyncApi> getApiContext()
+    {
+        return unwrap();
+    }
+
+    @Override
+    public AdministrationService getAdministrationService()
+    {
+        return administrationService;
+    }
+
+    @Override
+    public CloudService getCloudService()
+    {
+        return cloudService;
+    }
+
+    @Override
+    public SearchService getSearchService()
+    {
+        return searchService;
+    }
+
+    @Override
+    public MonitoringService getMonitoringService()
+    {
+        return monitoringService;
+    }
+
+    @Override
+    public EventService getEventService()
+    {
+        return eventService;
+    }
+
+    @Override
+    public PricingService getPricingService()
+    {
+        return pricingService;
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseAdministrationService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseAdministrationService.java
new file mode 100644
index 0000000..144efa4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseAdministrationService.java
@@ -0,0 +1,364 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.config.Category;
+import org.jclouds.abiquo.domain.config.License;
+import org.jclouds.abiquo.domain.config.Privilege;
+import org.jclouds.abiquo.domain.config.SystemProperty;
+import org.jclouds.abiquo.domain.config.options.LicenseOptions;
+import org.jclouds.abiquo.domain.config.options.PropertyOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.EnterpriseProperties;
+import org.jclouds.abiquo.domain.enterprise.Role;
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+import org.jclouds.abiquo.features.services.AdministrationService;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.strategy.admin.ListRoles;
+import org.jclouds.abiquo.strategy.config.ListCategories;
+import org.jclouds.abiquo.strategy.config.ListLicenses;
+import org.jclouds.abiquo.strategy.config.ListPrivileges;
+import org.jclouds.abiquo.strategy.config.ListProperties;
+import org.jclouds.abiquo.strategy.enterprise.ListEnterprises;
+import org.jclouds.abiquo.strategy.infrastructure.ListDatacenters;
+import org.jclouds.abiquo.strategy.infrastructure.ListMachines;
+import org.jclouds.collect.Memoized;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.EnterprisePropertiesDto;
+import com.abiquo.server.core.enterprise.RoleDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+
+/**
+ * Provides high level Abiquo administration operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class BaseAdministrationService implements AdministrationService
+{
+    @VisibleForTesting
+    protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @VisibleForTesting
+    protected final ListDatacenters listDatacenters;
+
+    @VisibleForTesting
+    protected final ListMachines listMachines;
+
+    @VisibleForTesting
+    protected final ListEnterprises listEnterprises;
+
+    @VisibleForTesting
+    protected final ListRoles listRoles;
+
+    @VisibleForTesting
+    protected final ListLicenses listLicenses;
+
+    @VisibleForTesting
+    protected final ListPrivileges listPrivileges;
+
+    @VisibleForTesting
+    protected final ListProperties listProperties;
+
+    @VisibleForTesting
+    protected final ListCategories listCategories;
+
+    @VisibleForTesting
+    protected final Supplier<User> currentUser;
+
+    @VisibleForTesting
+    protected final Supplier<Enterprise> currentEnterprise;
+
+    @Inject
+    protected BaseAdministrationService(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final ListDatacenters listDatacenters, final ListMachines listMachines,
+        final ListEnterprises listEnterprises, final ListRoles listRoles,
+        final ListLicenses listLicenses, final ListPrivileges listPrivileges,
+        final ListProperties listProperties, final ListCategories listCategories,
+        @Memoized final Supplier<User> currentUser,
+        @Memoized final Supplier<Enterprise> currentEnterprise)
+    {
+        this.context = checkNotNull(context, "context");
+        this.listDatacenters = checkNotNull(listDatacenters, "listDatacenters");
+        this.listMachines = checkNotNull(listMachines, "listMachines");
+        this.listEnterprises = checkNotNull(listEnterprises, "listEnterprises");
+        this.listRoles = checkNotNull(listRoles, "listRoles");
+        this.listLicenses = checkNotNull(listLicenses, "listLicenses");
+        this.listPrivileges = checkNotNull(listPrivileges, "listPrivileges");
+        this.listProperties = checkNotNull(listProperties, "listProperties");
+        this.listCategories = checkNotNull(listCategories, "listCategories");
+        this.currentUser = checkNotNull(currentUser, "currentUser");
+        this.currentEnterprise = checkNotNull(currentEnterprise, "currentEnterprise");
+    }
+
+    /*********************** Datacenter ********************** */
+
+    @Override
+    public Iterable<Datacenter> listDatacenters()
+    {
+        return listDatacenters.execute();
+    }
+
+    @Override
+    public Iterable<Datacenter> listDatacenters(final Predicate<Datacenter> filter)
+    {
+        return listDatacenters.execute(filter);
+    }
+
+    @Override
+    public Datacenter getDatacenter(final Integer datacenterId)
+    {
+        DatacenterDto datacenter =
+            context.getApi().getInfrastructureApi().getDatacenter(datacenterId);
+        return wrap(context, Datacenter.class, datacenter);
+    }
+
+    @Override
+    public Datacenter findDatacenter(final Predicate<Datacenter> filter)
+    {
+        return Iterables.getFirst(listDatacenters(filter), null);
+    }
+
+    @Override
+    public Iterable<Datacenter> getDatacenters(final List<Integer> datacenterIds)
+    {
+        return listDatacenters.execute(datacenterIds);
+    }
+
+    /*********************** Machine ***********************/
+
+    @Override
+    public Iterable<Machine> listMachines()
+    {
+        return listMachines.execute();
+    }
+
+    @Override
+    public Iterable<Machine> listMachines(final Predicate<Machine> filter)
+    {
+        return listMachines.execute(filter);
+    }
+
+    @Override
+    public Machine findMachine(final Predicate<Machine> filter)
+    {
+        return Iterables.getFirst(listMachines(filter), null);
+    }
+
+    /*********************** Enterprise ***********************/
+
+    @Override
+    public Iterable<Enterprise> listEnterprises()
+    {
+        return listEnterprises.execute();
+    }
+
+    @Override
+    public Iterable<Enterprise> listEnterprises(final Predicate<Enterprise> filter)
+    {
+        return listEnterprises.execute(filter);
+    }
+
+    @Override
+    public Enterprise findEnterprise(final Predicate<Enterprise> filter)
+    {
+        return Iterables.getFirst(listEnterprises(filter), null);
+    }
+
+    @Override
+    public Enterprise getEnterprise(final Integer enterpriseId)
+    {
+        EnterpriseDto enterprise =
+            context.getApi().getEnterpriseApi().getEnterprise(enterpriseId);
+        return wrap(context, Enterprise.class, enterprise);
+    }
+
+    /*********************** Enterprise Properties ***********************/
+
+    @Override
+    public EnterpriseProperties getEnterpriseProperties(final Enterprise enterprise)
+    {
+        checkNotNull(enterprise.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in "
+            + Enterprise.class);
+
+        EnterprisePropertiesDto properties =
+            context.getApi().getEnterpriseApi().getEnterpriseProperties(enterprise.unwrap());
+        return wrap(context, EnterpriseProperties.class, properties);
+    }
+
+    /*********************** Role ********************** */
+
+    @Override
+    public Iterable<Role> listRoles()
+    {
+        return listRoles.execute();
+    }
+
+    @Override
+    public Iterable<Role> listRoles(final Predicate<Role> filter)
+    {
+        return listRoles.execute(filter);
+    }
+
+    @Override
+    public Role findRole(final Predicate<Role> filter)
+    {
+        return Iterables.getFirst(listRoles(filter), null);
+    }
+
+    @Override
+    public Role getRole(final Integer roleId)
+    {
+        RoleDto role = context.getApi().getAdminApi().getRole(roleId);
+        return wrap(context, Role.class, role);
+    }
+
+    /*********************** Privilege ***********************/
+
+    @Override
+    public Privilege findPrivilege(final Predicate<Privilege> filter)
+    {
+        return Iterables.getFirst(listPrivileges(filter), null);
+    }
+
+    @Override
+    public Iterable<Privilege> listPrivileges()
+    {
+        return listPrivileges.execute();
+    }
+
+    @Override
+    public Iterable<Privilege> listPrivileges(final Predicate<Privilege> filter)
+    {
+        return listPrivileges.execute(filter);
+    }
+
+    /*********************** User ***********************/
+
+    @Override
+    public User getCurrentUser()
+    {
+        return currentUser.get();
+    }
+
+    @Override
+    public Enterprise getCurrentEnterprise()
+    {
+        return currentEnterprise.get();
+    }
+
+    /*********************** License ***********************/
+
+    @Override
+    public Iterable<License> listLicenses()
+    {
+        return listLicenses.execute();
+    }
+
+    @Override
+    public Iterable<License> listLicenses(final boolean active)
+    {
+        LicenseOptions options = LicenseOptions.builder().active(active).build();
+        return listLicenses.execute(options);
+    }
+
+    @Override
+    public Iterable<License> listLicenses(final Predicate<License> filter)
+    {
+        return listLicenses.execute(filter);
+    }
+
+    @Override
+    public License findLicense(final Predicate<License> filter)
+    {
+        return Iterables.getFirst(listLicenses(filter), null);
+    }
+
+    /*********************** System Properties ***********************/
+
+    @Override
+    public Iterable<SystemProperty> listSystemProperties()
+    {
+        return listProperties.execute();
+    }
+
+    @Override
+    public Iterable<SystemProperty> listSystemProperties(final Predicate<SystemProperty> filter)
+    {
+        return listProperties.execute(filter);
+    }
+
+    @Override
+    public SystemProperty findSystemProperty(final Predicate<SystemProperty> filter)
+    {
+        return Iterables.getFirst(listSystemProperties(filter), null);
+    }
+
+    @Override
+    public SystemProperty getSystemProperty(final String name)
+    {
+        PropertyOptions options = PropertyOptions.builder().name(name).build();
+        return Iterables.getFirst(listProperties.execute(options), null);
+    }
+
+    @Override
+    public Iterable<SystemProperty> listSystemProperties(final String component)
+    {
+        PropertyOptions options = PropertyOptions.builder().component(component).build();
+        return listProperties.execute(options);
+    }
+
+    @Override
+    public Category findCategory(final Predicate<Category> filter)
+    {
+        return Iterables.getFirst(listCategories(filter), null);
+    }
+
+    @Override
+    public Iterable<Category> listCategories()
+    {
+        return listCategories.execute();
+    }
+
+    @Override
+    public Iterable<Category> listCategories(final Predicate<Category> filter)
+    {
+        return listCategories.execute(filter);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseCloudService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseCloudService.java
new file mode 100644
index 0000000..b3ba313
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseCloudService.java
@@ -0,0 +1,171 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.options.VirtualDatacenterOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.features.services.CloudService;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualAppliances;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualDatacenters;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualMachines;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+/**
+ * Provides high level Abiquo cloud operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class BaseCloudService implements CloudService
+{
+    @VisibleForTesting
+    protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @VisibleForTesting
+    protected final ListVirtualDatacenters listVirtualDatacenters;
+
+    @VisibleForTesting
+    protected ListVirtualAppliances listVirtualAppliances;
+
+    @VisibleForTesting
+    protected ListVirtualMachines listVirtualMachines;
+
+    @Inject
+    protected BaseCloudService(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final ListVirtualDatacenters listVirtualDatacenters,
+        final ListVirtualAppliances listVirtualAppliances,
+        final ListVirtualMachines listVirtualMachines)
+    {
+        this.context = checkNotNull(context, "context");
+        this.listVirtualDatacenters =
+            checkNotNull(listVirtualDatacenters, "listVirtualDatacenters");
+        this.listVirtualAppliances = checkNotNull(listVirtualAppliances, "listVirtualAppliances");
+        this.listVirtualMachines = checkNotNull(listVirtualMachines, "listVirtualMachines");
+    }
+
+    /*********************** Virtual Datacenter ********************** */
+
+    @Override
+    public Iterable<VirtualDatacenter> listVirtualDatacenters()
+    {
+        return listVirtualDatacenters.execute();
+    }
+
+    @Override
+    public Iterable<VirtualDatacenter> listVirtualDatacenters(final Enterprise enterprise)
+    {
+        checkNotNull(enterprise, ValidationErrors.NULL_RESOURCE + Enterprise.class);
+        checkNotNull(enterprise.getId(), ValidationErrors.MISSING_REQUIRED_FIELD + " id in "
+            + Enterprise.class);
+
+        VirtualDatacenterOptions options =
+            VirtualDatacenterOptions.builder().enterpriseId(enterprise.getId()).build();
+
+        return listVirtualDatacenters.execute(options);
+    }
+
+    @Override
+    public Iterable<VirtualDatacenter> listVirtualDatacenters(
+        final Predicate<VirtualDatacenter> filter)
+    {
+        return listVirtualDatacenters.execute(filter);
+    }
+
+    @Override
+    public VirtualDatacenter getVirtualDatacenter(final Integer virtualDatacenterId)
+    {
+        VirtualDatacenterDto virtualDatacenter =
+            context.getApi().getCloudApi().getVirtualDatacenter(virtualDatacenterId);
+        return wrap(context, VirtualDatacenter.class, virtualDatacenter);
+    }
+
+    @Override
+    public Iterable<VirtualDatacenter> getVirtualDatacenters(
+        final List<Integer> virtualDatacenterIds)
+    {
+        return listVirtualDatacenters.execute(virtualDatacenterIds);
+    }
+
+    @Override
+    public VirtualDatacenter findVirtualDatacenter(final Predicate<VirtualDatacenter> filter)
+    {
+        return Iterables.getFirst(listVirtualDatacenters(filter), null);
+    }
+
+    /*********************** Virtual Appliance ********************** */
+
+    @Override
+    public Iterable<VirtualAppliance> listVirtualAppliances()
+    {
+        return listVirtualAppliances.execute();
+    }
+
+    @Override
+    public Iterable<VirtualAppliance> listVirtualAppliances(final Predicate<VirtualAppliance> filter)
+    {
+        return listVirtualAppliances.execute(filter);
+    }
+
+    @Override
+    public VirtualAppliance findVirtualAppliance(final Predicate<VirtualAppliance> filter)
+    {
+        return Iterables.getFirst(listVirtualAppliances(filter), null);
+    }
+
+    /*********************** Virtual Machine ********************** */
+
+    @Override
+    public Iterable<VirtualMachine> listVirtualMachines()
+    {
+        return listVirtualMachines.execute();
+    }
+
+    @Override
+    public Iterable<VirtualMachine> listVirtualMachines(final Predicate<VirtualMachine> filter)
+    {
+        return listVirtualMachines.execute(filter);
+    }
+
+    @Override
+    public VirtualMachine findVirtualMachine(final Predicate<VirtualMachine> filter)
+    {
+        return Iterables.getFirst(listVirtualMachines(filter), null);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseEventService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseEventService.java
new file mode 100644
index 0000000..2447cf5
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseEventService.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.event.Event;
+import org.jclouds.abiquo.domain.event.options.EventOptions;
+import org.jclouds.abiquo.features.services.EventService;
+import org.jclouds.abiquo.strategy.event.ListEvents;
+import org.jclouds.rest.RestContext;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Provides high level Abiquo event operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Vivien Mahé
+ */
+@Singleton
+public class BaseEventService implements EventService
+{
+    @VisibleForTesting
+    protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @VisibleForTesting
+    protected final ListEvents listEvents;
+
+    @Inject
+    protected BaseEventService(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final ListEvents listEvents)
+    {
+        this.context = checkNotNull(context, "context");
+        this.listEvents = checkNotNull(listEvents, "listEvents");
+    }
+
+    @Override
+    public Iterable<Event> listEvents()
+    {
+        return listEvents.execute();
+    }
+
+    @Override
+    public Iterable<Event> listEvents(final EventOptions options)
+    {
+        return listEvents.execute(options);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseMonitoringService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseMonitoringService.java
new file mode 100644
index 0000000..8d850ef
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseMonitoringService.java
@@ -0,0 +1,335 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.Constants.PROPERTY_SCHEDULER_THREADS;
+import static org.jclouds.abiquo.config.AbiquoProperties.ASYNC_TASK_MONITOR_DELAY;
+
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.events.handlers.AbstractEventHandler;
+import org.jclouds.abiquo.events.handlers.BlockingEventHandler;
+import org.jclouds.abiquo.events.monitor.CompletedEvent;
+import org.jclouds.abiquo.events.monitor.FailedEvent;
+import org.jclouds.abiquo.events.monitor.TimeoutEvent;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.monitor.AsyncTaskMonitor;
+import org.jclouds.abiquo.monitor.ConversionMonitor;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.abiquo.monitor.VirtualApplianceMonitor;
+import org.jclouds.abiquo.monitor.VirtualMachineMonitor;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.eventbus.EventBus;
+import com.google.inject.Inject;
+
+/**
+ * Utility service to monitor asynchronous operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class BaseMonitoringService implements MonitoringService
+{
+    @VisibleForTesting
+    protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    /** The scheduler used to perform monitoring tasks. */
+    @VisibleForTesting
+    protected ScheduledExecutorService scheduler;
+
+    @VisibleForTesting
+    protected Long pollingDelay;
+
+    /**
+     * The event bus used to dispatch monitoring events.
+     * <p>
+     * A sync bus is used by default, to prevent deadlocks when using the
+     * {@link BlockingEventHandler}.
+     */
+    @VisibleForTesting
+    protected EventBus eventBus;
+
+    @Resource
+    private Logger logger = Logger.NULL;
+
+    @Inject
+    public BaseMonitoringService(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(PROPERTY_SCHEDULER_THREADS) final ScheduledExecutorService scheduler,
+        @Named(ASYNC_TASK_MONITOR_DELAY) final Long pollingDelay, final EventBus eventBus)
+    {
+        this.context = checkNotNull(context, "context");
+        this.scheduler = checkNotNull(scheduler, "scheduler");
+        this.pollingDelay = checkNotNull(pollingDelay, "pollingDelay");
+        this.eventBus = checkNotNull(eventBus, "eventBus");
+    }
+
+    /*************** Generic monitoring methods ***************/
+
+    @Override
+    public <T> void awaitCompletion(final Function<T, MonitorStatus> completeCondition,
+        final T... objects)
+    {
+        awaitCompletion(null, null, completeCondition, objects);
+    }
+
+    @Override
+    public <T> void awaitCompletion(final Long maxWait, final TimeUnit timeUnit,
+        final Function<T, MonitorStatus> completeCondition, final T... objects)
+    {
+        checkNotNull(completeCondition, "completeCondition");
+
+        if (objects != null && objects.length > 0)
+        {
+            BlockingEventHandler<T> blockingHandler = new BlockingEventHandler<T>(logger, objects);
+            register(blockingHandler);
+
+            monitor(maxWait, timeUnit, completeCondition, objects);
+            blockingHandler.lock();
+
+            unregister(blockingHandler);
+        }
+    }
+
+    @Override
+    public <T> void monitor(final Function<T, MonitorStatus> completeCondition, final T... objects)
+    {
+        monitor(null, null, completeCondition, objects);
+    }
+
+    @Override
+    public <T> void monitor(final Long maxWait, final TimeUnit timeUnit,
+        final Function<T, MonitorStatus> completeCondition, final T... objects)
+    {
+        checkNotNull(completeCondition, "completeCondition");
+        if (maxWait != null)
+        {
+            checkNotNull(timeUnit, "timeUnit");
+        }
+
+        if (objects != null && objects.length > 0)
+        {
+            for (T object : objects)
+            {
+                AsyncMonitor<T> monitor = new AsyncMonitor<T>(object, completeCondition);
+                monitor.startMonitoring(maxWait);
+            }
+        }
+    }
+
+    @Override
+    public <T extends AbstractEventHandler< ? >> void register(final T handler)
+    {
+        logger.debug("registering event handler %s", handler);
+        eventBus.register(handler);
+    }
+
+    @Override
+    public <T extends AbstractEventHandler< ? >> void unregister(final T handler)
+    {
+        logger.debug("unregistering event handler %s", handler);
+        eventBus.unregister(handler);
+    }
+
+    /*************** Delegating monitors ***************/
+
+    @Override
+    public VirtualMachineMonitor getVirtualMachineMonitor()
+    {
+        return checkNotNull(
+            context.getUtils().getInjector().getInstance(VirtualMachineMonitor.class),
+            "virtualMachineMonitor");
+    }
+
+    @Override
+    public VirtualApplianceMonitor getVirtualApplianceMonitor()
+    {
+        return checkNotNull(
+            context.getUtils().getInjector().getInstance(VirtualApplianceMonitor.class),
+            "virtualApplianceMonitor");
+    }
+
+    @Override
+    public AsyncTaskMonitor getAsyncTaskMonitor()
+    {
+        return checkNotNull(context.getUtils().getInjector().getInstance(AsyncTaskMonitor.class),
+            "asyncTaskMonitor");
+    }
+
+    @Override
+    public ConversionMonitor getConversionMonitor()
+    {
+        return checkNotNull(context.getUtils().getInjector().getInstance(ConversionMonitor.class),
+            "conversionMonitor");
+    }
+
+    /**
+     * Performs the periodical monitoring tasks.
+     * 
+     * @author Ignasi Barrera
+     * @param <T> The type of the object being monitored.
+     */
+    @VisibleForTesting
+    class AsyncMonitor<T> implements Runnable
+    {
+        /** The object being monitored. */
+        private T monitoredObject;
+
+        /** The function used to monitor the target object. */
+        private Function<T, MonitorStatus> completeCondition;
+
+        /**
+         * The future representing the monitoring job. Needed to be able to cancel it when monitor
+         * finishes.
+         */
+        private Future< ? > future;
+
+        /** The timeout for this monitor. */
+        private Long timeout;
+
+        public AsyncMonitor(final T monitoredObject,
+            final Function<T, MonitorStatus> completeCondition)
+        {
+            super();
+            this.monitoredObject = checkNotNull(monitoredObject, "monitoredObject");
+            this.completeCondition = checkNotNull(completeCondition, "completeCondition");
+        }
+
+        /**
+         * Starts the monitoring job with the given timeout.
+         * 
+         * @param maxWait The timeout.
+         */
+        public void startMonitoring(final Long maxWait)
+        {
+            future =
+                scheduler.scheduleWithFixedDelay(this, 0L, pollingDelay, TimeUnit.MILLISECONDS);
+            timeout = maxWait == null ? null : System.currentTimeMillis() + maxWait;
+            logger.debug("started monitor job for %s with %s timeout", monitoredObject,
+                timeout == null ? "no" : String.valueOf(timeout));
+        }
+
+        /**
+         * Stops the monitoring job, if running.
+         */
+        public void stopMonitoring()
+        {
+            logger.debug("stopping monitor job for %s", monitoredObject);
+
+            try
+            {
+                if (future != null && !future.isCancelled() && !future.isDone())
+                {
+                    // Do not force future cancel. Let it finish gracefully
+                    logger.debug("cancelling future");
+                    future.cancel(false);
+                }
+            }
+            catch (Exception ex)
+            {
+                logger.warn(ex, "failed to stop monitor job for %s", monitoredObject);
+            }
+        }
+
+        /**
+         * Checks if the monitor has timed out.
+         */
+        public boolean isTimeout()
+        {
+            return timeout != null && timeout < System.currentTimeMillis();
+        }
+
+        @Override
+        public void run()
+        {
+            // Do not use Thread.interrupted() since it will clear the interrupted flag
+            // and subsequent calls to it may not return the appropriate value
+            if (Thread.currentThread().isInterrupted())
+            {
+                // If the thread as already been interrupted, just stop monitoring the task and
+                // return
+                stopMonitoring();
+                return;
+            }
+
+            MonitorStatus status = completeCondition.apply(monitoredObject);
+            logger.debug("monitored object %s status %s", monitoredObject, status.name());
+
+            switch (status)
+            {
+                case DONE:
+                    stopMonitoring();
+                    logger.debug("publishing COMPLETED event");
+                    eventBus.post(new CompletedEvent<T>(monitoredObject));
+                    break;
+                case FAILED:
+                    stopMonitoring();
+                    logger.debug("publishing FAILED event");
+                    eventBus.post(new FailedEvent<T>(monitoredObject));
+                    break;
+                case CONTINUE:
+                default:
+                    if (isTimeout())
+                    {
+                        logger.warn("monitor for object %s timed out. Shutting down monitor.",
+                            monitoredObject);
+                        stopMonitoring();
+                        logger.debug("publishing TIMEOUT event");
+                        eventBus.post(new TimeoutEvent<T>(monitoredObject));
+                    }
+                    break;
+            }
+        }
+
+        public T getMonitoredObject()
+        {
+            return monitoredObject;
+        }
+
+        public Function<T, MonitorStatus> getCompleteCondition()
+        {
+            return completeCondition;
+        }
+
+        public Future< ? > getFuture()
+        {
+            return future;
+        }
+
+        public Long getTimeout()
+        {
+            return timeout;
+        }
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BasePricingService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BasePricingService.java
new file mode 100644
index 0000000..c879374
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BasePricingService.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.config.Currency;
+import org.jclouds.abiquo.features.services.PricingService;
+import org.jclouds.abiquo.strategy.config.ListCurrencies;
+import org.jclouds.rest.RestContext;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+/**
+ * Provides high level Abiquo administration operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ */
+@Singleton
+public class BasePricingService implements PricingService
+{
+    @VisibleForTesting
+    protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @VisibleForTesting
+    protected final ListCurrencies listCurrencies;
+
+    @Inject
+    protected BasePricingService(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final ListCurrencies listCurrencies)
+    {
+        this.context = checkNotNull(context, "context");
+        this.listCurrencies = checkNotNull(listCurrencies, "listCurrencies");
+    }
+
+    /*********************** Currency ********************** */
+
+    @Override
+    public Iterable<Currency> listCurrencies()
+    {
+        return listCurrencies.execute();
+    }
+
+    @Override
+    public Iterable<Currency> listCurrencies(final Predicate<Currency> filter)
+    {
+        return listCurrencies.execute(filter);
+    }
+
+    @Override
+    public Currency findCurrency(final Predicate<Currency> filter)
+    {
+        return Iterables.getFirst(listCurrencies(filter), null);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseSearchService.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseSearchService.java
new file mode 100644
index 0000000..57d8c66
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/internal/BaseSearchService.java
@@ -0,0 +1,182 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.Volume;
+import org.jclouds.abiquo.domain.cloud.options.VolumeOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.options.EnterpriseOptions;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.LogicServer;
+import org.jclouds.abiquo.domain.infrastructure.ManagedRack;
+import org.jclouds.abiquo.domain.infrastructure.StorageDevice;
+import org.jclouds.abiquo.domain.infrastructure.StoragePool;
+import org.jclouds.abiquo.domain.infrastructure.options.StoragePoolOptions;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PrivateNetwork;
+import org.jclouds.abiquo.domain.network.PublicIp;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.domain.options.search.FilterOptions;
+import org.jclouds.abiquo.features.services.SearchService;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Provides high level Abiquo search, filter and pagination operations.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class BaseSearchService implements SearchService
+{
+    @VisibleForTesting
+    protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    protected BaseSearchService(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = checkNotNull(context, "context");
+    }
+
+    /*********************** Enterprise ***********************/
+
+    @Override
+    public Iterable<Enterprise> searchEnterprises(final EnterpriseOptions options)
+    {
+        List<EnterpriseDto> enterprises =
+            context.getApi().getEnterpriseApi().listEnterprises(options).getCollection();
+
+        return wrap(context, Enterprise.class, enterprises);
+    }
+
+    @Override
+    public Iterable<Enterprise> searchEnterprisesUsingDatacenter(final Datacenter datacenter,
+        final EnterpriseOptions options)
+    {
+        List<EnterpriseDto> enterprises =
+            context.getApi().getEnterpriseApi().listEnterprises(datacenter.unwrap(), options)
+                .getCollection();
+
+        return wrap(context, Enterprise.class, enterprises);
+    }
+
+    /*********************** Volume ********************** */
+
+    @Override
+    public Iterable<Volume> searchVolumes(final VirtualDatacenter virtualDatacenter,
+        final VolumeOptions options)
+    {
+        List<VolumeManagementDto> volumes =
+            context.getApi().getCloudApi().listVolumes(virtualDatacenter.unwrap(), options)
+                .getCollection();
+
+        return wrap(context, Volume.class, volumes);
+    }
+
+    /*********************** Storage Pool ***********************/
+
+    @Override
+    public List<StoragePool> searchStoragePools(final StorageDevice device,
+        final StoragePoolOptions options)
+    {
+        List<StoragePoolDto> pools =
+            context.getApi().getInfrastructureApi().listStoragePools(device.unwrap(), options)
+                .getCollection();
+
+        return wrap(context, StoragePool.class, pools);
+    }
+
+    /*********************** Private Network ***********************/
+
+    @Override
+    public Iterable<PrivateIp> searchPrivateIps(final PrivateNetwork network,
+        final IpOptions options)
+    {
+        List<PrivateIpDto> ips =
+            context.getApi().getCloudApi().listPrivateNetworkIps(network.unwrap(), options)
+                .getCollection();
+
+        return wrap(context, PrivateIp.class, ips);
+    }
+
+    @Override
+    public Iterable<PublicIp> searchPublicIpsToPurchase(final VirtualDatacenter virtualDatacenter,
+        final IpOptions options)
+    {
+        List<PublicIpDto> ips =
+            context.getApi().getCloudApi()
+                .listAvailablePublicIps(virtualDatacenter.unwrap(), options).getCollection();
+
+        return wrap(context, PublicIp.class, ips);
+    }
+
+    @Override
+    public Iterable<PublicIp> searchPurchasedPublicIps(final VirtualDatacenter virtualDatacenter,
+        final IpOptions options)
+    {
+        List<PublicIpDto> ips =
+            context.getApi().getCloudApi()
+                .listPurchasedPublicIps(virtualDatacenter.unwrap(), options).getCollection();
+
+        return wrap(context, PublicIp.class, ips);
+    }
+
+    @Override
+    public Iterable<LogicServer> searchServiceProfiles(final ManagedRack rack,
+        final FilterOptions options)
+    {
+        List<LogicServerDto> profiles =
+            context.getApi().getInfrastructureApi().listServiceProfiles(rack.unwrap(), options)
+                .getCollection();
+
+        return wrap(context, LogicServer.class, profiles);
+    }
+
+    @Override
+    public Iterable<LogicServer> searchServiceProfileTemplates(final ManagedRack rack,
+        final FilterOptions options)
+    {
+        List<LogicServerDto> profiles =
+            context.getApi().getInfrastructureApi()
+                .listServiceProfileTemplates(rack.unwrap(), options).getCollection();
+
+        return wrap(context, LogicServer.class, profiles);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/AsyncTaskMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/AsyncTaskMonitor.java
new file mode 100644
index 0000000..d9b7c7f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/AsyncTaskMonitor.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.monitor.internal.BaseAsyncTaskMonitor;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * {@link VirtualMachine} monitoring features.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(BaseAsyncTaskMonitor.class)
+public interface AsyncTaskMonitor extends MonitoringService
+{
+    /**
+     * Monitor the given {@link AsyncTask}s and block until they finishe.
+     * 
+     * @param tasks The {@link AsyncTask}s to monitor.
+     */
+    void awaitCompletion(final AsyncTask... tasks);
+
+    /**
+     * Monitor the given {@link AsyncTask}s and populate an event when they finish.
+     * 
+     * @param tasks The {@link AsyncTask}s to monitor.
+     */
+    public void monitor(final AsyncTask... tasks);
+
+    /**
+     * Monitor the given {@link AsyncTask}s and block until they finish.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param tasks The {@link AsyncTask}s to monitor.
+     */
+    void awaitCompletion(final Long maxWait, final TimeUnit timeUnit, final AsyncTask... tasks);
+
+    /**
+     * Monitor the given {@link AsyncTask}s and populate an event when they finish.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param tasks The {@link AsyncTask}s to monitor.
+     */
+    public void monitor(final Long maxWait, final TimeUnit timeUnit, final AsyncTask... tasks);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/ConversionMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/ConversionMonitor.java
new file mode 100644
index 0000000..5910cfe
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/ConversionMonitor.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.cloud.Conversion;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.monitor.internal.BaseConversionMonitor;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * {@link Conversion} monitoring features.
+ * 
+ * @author Sergi Castro
+ */
+@ImplementedBy(BaseConversionMonitor.class)
+public interface ConversionMonitor extends MonitoringService
+{
+    /**
+     * Monitor the given {@link Conversion}s and block until they finishes.
+     * 
+     * @param conversions The {@link Conversion}s to monitor.
+     */
+    void awaitCompletion(final Conversion... conversions);
+
+    /**
+     * Monitor the given {@link Conversion}s and populate an event when they finish.
+     * 
+     * @param conversions The {@link Conversion}s to monitor.
+     */
+    public void monitor(final Conversion... conversions);
+
+    /**
+     * Monitor the given {@link Conversion}s and block until they finish.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param conversions The {@link Conversion}s to monitor.
+     */
+    void awaitCompletion(final Long maxWait, final TimeUnit timeUnit,
+        final Conversion... conversions);
+
+    /**
+     * Monitor the given {@link Conversion}s and populate an event when they finish.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param conversions The {@link Conversion}s to monitor.
+     */
+    public void monitor(final Long maxWait, final TimeUnit timeUnit,
+        final Conversion... conversions);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/MonitorStatus.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/MonitorStatus.java
new file mode 100644
index 0000000..b535164
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/MonitorStatus.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor;
+
+/**
+ * Represents the states of a running monitor.
+ * 
+ * @author Serafin Sedano
+ */
+public enum MonitorStatus
+{
+    /** The monitoring job has finished. */
+    DONE,
+
+    /** The monitoring job has finished and the result is not the expected one. */
+    FAILED,
+
+    /** The monitoring job must continue. */
+    CONTINUE
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/VirtualApplianceMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/VirtualApplianceMonitor.java
new file mode 100644
index 0000000..b6088af
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/VirtualApplianceMonitor.java
@@ -0,0 +1,107 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.monitor.internal.BaseVirtualApplianceMonitor;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * {@link VirtualAppliance} monitoring features.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(BaseVirtualApplianceMonitor.class)
+public interface VirtualApplianceMonitor extends MonitoringService
+{
+    /**
+     * Monitor the given {@link VirtualAppliance}s and block until the deploy finishes.
+     * 
+     * @param vapp The {@link VirtualAppliance}s to monitor.
+     */
+    void awaitCompletionDeploy(final VirtualAppliance... vapp);
+
+    /**
+     * Monitor the given {@link VirtualAppliance}s and populate an event when the deploy finishes.
+     * 
+     * @param VirtualAppliance The {@link VirtualAppliance}s to monitor.
+     */
+    public void monitorDeploy(final VirtualAppliance... vapps);
+
+    /**
+     * Monitor the given {@link VirtualAppliance}s and block until the deploy finishes.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param vapp The {@link VirtualAppliance}s to monitor.
+     */
+    void awaitCompletionDeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualAppliance... vapp);
+
+    /**
+     * Monitor the given {@link VirtualAppliance}s and populate an event when deploy finishes.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param vapps The {@link VirtualAppliance}s to monitor.
+     */
+    public void monitorDeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualAppliance... vapps);
+
+    /**
+     * Monitor the given {@link VirtualAppliance}s and block until the undeploy finishes.
+     * 
+     * @param vapp The {@link VirtualAppliance}s to monitor.
+     */
+    void awaitCompletionUndeploy(final VirtualAppliance... vapp);
+
+    /**
+     * Monitor the given {@link VirtualAppliance}s and call populate an event when undeploy
+     * finishes.
+     * 
+     * @param vapps The {@link VirtualAppliance}s to monitor.
+     */
+    public void monitorUndeploy(final VirtualAppliance... vapps);
+
+    /**
+     * Monitor the given {@link VirtualAppliance}s and blocks until the undeploy finishes.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param vapp The {@link VirtualAppliance}s to monitor.
+     */
+    void awaitCompletionUndeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualAppliance... vapp);
+
+    /**
+     * Monitor the given {@link VirtualAppliance}s and populate an event when undeploy finishes.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param callback The callback.
+     * @param vapps The {@link VirtualAppliance}s to monitor.
+     */
+    public void monitorUndeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualAppliance... vapps);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/VirtualMachineMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/VirtualMachineMonitor.java
new file mode 100644
index 0000000..74d488e
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/VirtualMachineMonitor.java
@@ -0,0 +1,144 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.monitor.internal.BaseVirtualMachineMonitor;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.inject.ImplementedBy;
+
+/**
+ * {@link VirtualMachine} monitoring features.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(BaseVirtualMachineMonitor.class)
+public interface VirtualMachineMonitor extends MonitoringService
+{
+    /**
+     * Monitor the given {@link VirtualMachine}s and block until all deploys finish.
+     * 
+     * @param vm The {@link VirtualMachine}s to monitor.
+     */
+    void awaitCompletionDeploy(final VirtualMachine... vm);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and populate an event when all deploys finish.
+     * 
+     * @param vms The {@link VirtualMachine}s to monitor.
+     */
+    public void monitorDeploy(final VirtualMachine... vms);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and block until all deploys finish.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param vm The {@link VirtualMachine}s to monitor.
+     */
+    void awaitCompletionDeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachine... vm);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and populate an event when all deploys finish.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param vms The {@link VirtualMachine}s to monitor.
+     */
+    public void monitorDeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachine... vms);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and block until all undeploys finish.
+     * 
+     * @param vm The {@link VirtualMachine}s to monitor.
+     */
+    void awaitCompletionUndeploy(final VirtualMachine... vm);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and populate an event when all undeploys finish.
+     * 
+     * @param vms The {@link VirtualMachine}s to monitor.
+     */
+    public void monitorUndeploy(final VirtualMachine... vms);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and blocks until all undeploys finish.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param vm The {@link VirtualMachine}s to monitor.
+     */
+    void awaitCompletionUndeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachine... vm);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and populate an event when all undeploys finish.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param callback The callback.
+     * @param vms The {@link VirtualMachine}s to monitor.
+     */
+    public void monitorUndeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachine... vms);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and block until it is in the given state.
+     * 
+     * @param vm The {@link VirtualMachine}s to monitor.
+     */
+    void awaitState(VirtualMachineState state, final VirtualMachine... vm);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and populate an event when it is in the given
+     * state.
+     * 
+     * @param vms The {@link VirtualMachine}s to monitor.
+     */
+    public void monitorState(VirtualMachineState state, final VirtualMachine... vms);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and block until it is in the given state.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param vm The {@link VirtualMachine}s to monitor.
+     */
+    void awaitState(final Long maxWait, final TimeUnit timeUnit, VirtualMachineState state,
+        final VirtualMachine... vm);
+
+    /**
+     * Monitor the given {@link VirtualMachine}s and populate an event when it is in the given
+     * state.
+     * 
+     * @param maxWait The maximum time to wait.
+     * @param timeUnit The time unit for the maxWait parameter.
+     * @param callback The callback.
+     * @param vms The {@link VirtualMachine}s to monitor.
+     */
+    public void monitorState(final Long maxWait, final TimeUnit timeUnit,
+        VirtualMachineState state, final VirtualMachine... vms);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitor.java
new file mode 100644
index 0000000..5e18eb2
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitor.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+
+/**
+ * This class takes care of monitoring {@link AsyncTask} jobs.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class AsyncTaskStatusMonitor implements Function<AsyncTask, MonitorStatus>
+{
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Override
+    public MonitorStatus apply(final AsyncTask asyncTask)
+    {
+        checkNotNull(asyncTask, "asyncTask");
+
+        try
+        {
+            asyncTask.refresh();
+
+            switch (asyncTask.getState())
+            {
+                case ABORTED:
+                case FINISHED_UNSUCCESSFULLY:
+                    return MonitorStatus.FAILED;
+                case FINISHED_SUCCESSFULLY:
+                    return MonitorStatus.DONE;
+                case STARTED:
+                case PENDING:
+                    return MonitorStatus.CONTINUE;
+                default:
+                    throw new IllegalStateException("Unsupported task status");
+            }
+        }
+        catch (Exception ex)
+        {
+            logger.warn(ex, "exception thrown while monitoring %s on %s, returning CONTINUE",
+                asyncTask, getClass().getName());
+
+            return MonitorStatus.CONTINUE;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/ConversionStatusMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/ConversionStatusMonitor.java
new file mode 100644
index 0000000..a97e38e
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/ConversionStatusMonitor.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.cloud.Conversion;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.logging.Logger;
+
+import com.google.common.base.Function;
+
+/**
+ * This class takes care of monitoring {@link Conversion} jobs.
+ * 
+ * @author Sergi Castro
+ */
+@Singleton
+public class ConversionStatusMonitor implements Function<Conversion, MonitorStatus>
+{
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Override
+    public MonitorStatus apply(final Conversion conversion)
+    {
+        checkNotNull(conversion, "conversion");
+
+        try
+        {
+            conversion.refresh();
+
+            switch (conversion.getState())
+            {
+                case ENQUEUED:
+                    return MonitorStatus.CONTINUE;
+                case FAILED:
+                    return MonitorStatus.FAILED;
+                case FINISHED:
+                    return MonitorStatus.DONE;
+                default:
+                    throw new IllegalStateException("Unsupported conversion status");
+            }
+        }
+        catch (Exception ex)
+        {
+            logger.warn(ex, "exception thrown while monitoring %s on %s, returning CONTINUE",
+                conversion, getClass().getName());
+
+            return MonitorStatus.CONTINUE;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceDeployMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceDeployMonitor.java
new file mode 100644
index 0000000..d02f925
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceDeployMonitor.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.logging.Logger;
+
+import com.abiquo.server.core.cloud.VirtualApplianceState;
+import com.google.common.base.Function;
+
+/**
+ * This class takes care of monitoring the a deploy of a {@link VirtualAppliance}.
+ * 
+ * @author Serafin Sedano
+ */
+@Singleton
+public class VirtualApplianceDeployMonitor implements Function<VirtualAppliance, MonitorStatus>
+{
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Override
+    public MonitorStatus apply(final VirtualAppliance virtualAppliance)
+    {
+        checkNotNull(virtualAppliance, "virtualAppliance");
+
+        try
+        {
+            VirtualApplianceState state = virtualAppliance.getState();
+
+            switch (state)
+            {
+                case UNKNOWN:
+                case NEEDS_SYNC:
+                case NOT_DEPLOYED:
+                    return MonitorStatus.FAILED;
+                case DEPLOYED:
+                    return MonitorStatus.DONE;
+                case LOCKED:
+                default:
+                    return MonitorStatus.CONTINUE;
+            }
+        }
+        catch (Exception ex)
+        {
+            logger.warn(ex, "exception thrown while monitoring %s on %s, returning CONTINUE",
+                virtualAppliance, getClass().getName());
+
+            return MonitorStatus.CONTINUE;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceUndeployMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceUndeployMonitor.java
new file mode 100644
index 0000000..4951a4f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceUndeployMonitor.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.abiquo.server.core.cloud.VirtualApplianceState;
+import com.google.common.base.Function;
+
+/**
+ * This class takes care of monitoring the a undeploy of a {@link VirtualAppliance}.
+ * 
+ * @author Serafin Sedano
+ */
+@Singleton
+public class VirtualApplianceUndeployMonitor implements Function<VirtualAppliance, MonitorStatus>
+{
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Override
+    public MonitorStatus apply(final VirtualAppliance virtualAppliance)
+    {
+        checkNotNull(virtualAppliance, "virtualAppliance");
+
+        try
+        {
+            VirtualApplianceState state = virtualAppliance.getState();
+
+            switch (state)
+            {
+                case DEPLOYED:
+                case UNKNOWN:
+                case NEEDS_SYNC:
+                    return MonitorStatus.FAILED;
+                case NOT_DEPLOYED:
+                    return MonitorStatus.DONE;
+                case LOCKED:
+                default:
+                    return MonitorStatus.CONTINUE;
+            }
+        }
+        catch (ResourceNotFoundException nfe)
+        {
+            logger.warn("virtual appliance %s not found, assuming it was undeployed successfully, "
+                + "stop monitor with DONE", virtualAppliance);
+            return MonitorStatus.DONE;
+        }
+        catch (Exception ex)
+        {
+            logger.warn(ex, "exception thrown while monitoring %s on %s, returning CONTINUE",
+                virtualAppliance, getClass().getName());
+
+            return MonitorStatus.CONTINUE;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineDeployMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineDeployMonitor.java
new file mode 100644
index 0000000..0befb07
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineDeployMonitor.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.logging.Logger;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.common.base.Function;
+import com.google.inject.Singleton;
+
+/**
+ * This class takes care of monitoring the a deploy of a {@link VirtualMachine}.
+ * 
+ * @author Serafin Sedano
+ * @see MonitoringService
+ */
+@Singleton
+public class VirtualMachineDeployMonitor implements Function<VirtualMachine, MonitorStatus>
+{
+    @Resource
+    private Logger logger = Logger.NULL;
+
+    @Override
+    public MonitorStatus apply(final VirtualMachine virtualMachine)
+    {
+        checkNotNull(virtualMachine, "virtualMachine");
+
+        try
+        {
+            VirtualMachineState state = virtualMachine.getState();
+
+            switch (state)
+            {
+                case NOT_ALLOCATED:
+                case UNKNOWN:
+                    return MonitorStatus.FAILED;
+                case ON:
+                    return MonitorStatus.DONE;
+                default:
+                    return MonitorStatus.CONTINUE;
+            }
+        }
+        catch (Exception ex)
+        {
+            logger.warn(ex, "exception thrown while monitoring %s on %s, returning CONTINUE",
+                virtualMachine, getClass().getName());
+
+            return MonitorStatus.CONTINUE;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineStateMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineStateMonitor.java
new file mode 100644
index 0000000..869b959
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineStateMonitor.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.logging.Logger;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.common.base.Function;
+
+/**
+ * This class takes care of monitoring the state of a {@link VirtualMachine}.
+ * 
+ * @author Ignasi Barrera
+ * @see MonitoringService
+ */
+public class VirtualMachineStateMonitor implements Function<VirtualMachine, MonitorStatus>
+{
+    @Resource
+    private Logger logger = Logger.NULL;
+
+    private VirtualMachineState expectedState;
+
+    public VirtualMachineStateMonitor(final VirtualMachineState expectedState)
+    {
+        super();
+        this.expectedState = checkNotNull(expectedState, "expectedState");
+    }
+
+    @Override
+    public MonitorStatus apply(final VirtualMachine virtualMachine)
+    {
+        checkNotNull(virtualMachine, "virtualMachine");
+
+        try
+        {
+            VirtualMachineState state = virtualMachine.getState();
+            return state == expectedState ? MonitorStatus.DONE : MonitorStatus.CONTINUE;
+        }
+        catch (Exception ex)
+        {
+            logger.warn(ex, "exception thrown while monitoring %s on %s, returning CONTINUE",
+                virtualMachine, getClass().getName());
+
+            return MonitorStatus.CONTINUE;
+
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineUndeployMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineUndeployMonitor.java
new file mode 100644
index 0000000..b82006c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/VirtualMachineUndeployMonitor.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Resource;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.ResourceNotFoundException;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.common.base.Function;
+
+/**
+ * This class takes care of monitoring the a undeploy of a {@link VirtualMachine}.
+ * 
+ * @author Serafin Sedano
+ */
+@Singleton
+public class VirtualMachineUndeployMonitor implements Function<VirtualMachine, MonitorStatus>
+{
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Override
+    public MonitorStatus apply(final VirtualMachine virtualMachine)
+    {
+        checkNotNull(virtualMachine, "virtualMachine");
+
+        try
+        {
+            VirtualMachineState state = virtualMachine.getState();
+
+            // This state may be reached if the undeploy process fails and a rollback is done
+            if (state.existsInHypervisor())
+            {
+                return MonitorStatus.FAILED;
+            }
+
+            switch (state)
+            {
+                case UNKNOWN:
+                    return MonitorStatus.FAILED;
+                case NOT_ALLOCATED:
+                    return MonitorStatus.DONE;
+                default:
+                    return MonitorStatus.CONTINUE;
+            }
+        }
+        catch (ResourceNotFoundException nfe)
+        {
+            logger.warn("virtual machine %s not found, assuming it was undeployed successfully, "
+                + "stop monitor with DONE", virtualMachine);
+            return MonitorStatus.DONE;
+        }
+        catch (Exception ex)
+        {
+            logger.warn(ex, "exception thrown while monitoring %s on %s, returning CONTINUE",
+                virtualMachine, getClass().getName());
+
+            return MonitorStatus.CONTINUE;
+        }
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitor.java
new file mode 100644
index 0000000..f6e88c0
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitor.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.Constants.PROPERTY_SCHEDULER_THREADS;
+import static org.jclouds.abiquo.config.AbiquoProperties.ASYNC_TASK_MONITOR_DELAY;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.internal.BaseMonitoringService;
+import org.jclouds.abiquo.monitor.AsyncTaskMonitor;
+import org.jclouds.abiquo.monitor.functions.AsyncTaskStatusMonitor;
+import org.jclouds.rest.RestContext;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.eventbus.EventBus;
+
+/**
+ * Default monitor for {@link AsyncTask} objects.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BaseAsyncTaskMonitor extends BaseMonitoringService implements AsyncTaskMonitor
+{
+
+    @VisibleForTesting
+    protected AsyncTaskStatusMonitor taskMonitor;
+
+    @Inject
+    public BaseAsyncTaskMonitor(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(PROPERTY_SCHEDULER_THREADS) final ScheduledExecutorService scheduler,
+        @Named(ASYNC_TASK_MONITOR_DELAY) final Long pollingDelay, final EventBus eventBus,
+        final AsyncTaskStatusMonitor monitor)
+    {
+        super(context, scheduler, pollingDelay, eventBus);
+        this.taskMonitor = checkNotNull(monitor, "monitor");
+    }
+
+    @Override
+    public void awaitCompletion(final AsyncTask... tasks)
+    {
+        awaitCompletion(taskMonitor, tasks);
+    }
+
+    @Override
+    public void monitor(final AsyncTask... tasks)
+    {
+        monitor(taskMonitor, tasks);
+    }
+
+    @Override
+    public void awaitCompletion(final Long maxWait, final TimeUnit timeUnit,
+        final AsyncTask... tasks)
+    {
+        awaitCompletion(maxWait, timeUnit, taskMonitor, tasks);
+    }
+
+    @Override
+    public void monitor(final Long maxWait, final TimeUnit timeUnit, final AsyncTask... tasks)
+    {
+        monitor(maxWait, timeUnit, taskMonitor, tasks);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseConversionMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseConversionMonitor.java
new file mode 100644
index 0000000..b30be3a
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseConversionMonitor.java
@@ -0,0 +1,92 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.Constants.PROPERTY_SCHEDULER_THREADS;
+import static org.jclouds.abiquo.config.AbiquoProperties.ASYNC_TASK_MONITOR_DELAY;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.cloud.Conversion;
+import org.jclouds.abiquo.internal.BaseMonitoringService;
+import org.jclouds.abiquo.monitor.ConversionMonitor;
+import org.jclouds.abiquo.monitor.functions.ConversionStatusMonitor;
+import org.jclouds.rest.RestContext;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.eventbus.EventBus;
+
+/**
+ * Default monitor for {@link Conversion} objects.
+ * 
+ * @author Sergi Castro
+ */
+@Singleton
+public class BaseConversionMonitor extends BaseMonitoringService implements ConversionMonitor
+{
+
+    @VisibleForTesting
+    protected ConversionStatusMonitor conversionMonitor;
+
+    @Inject
+    public BaseConversionMonitor(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(PROPERTY_SCHEDULER_THREADS) final ScheduledExecutorService scheduler,
+        @Named(ASYNC_TASK_MONITOR_DELAY) final Long pollingDelay, final EventBus eventBus,
+        final ConversionStatusMonitor monitor)
+    {
+        super(context, scheduler, pollingDelay, eventBus);
+        this.conversionMonitor = checkNotNull(monitor, "monitor");
+    }
+
+    @Override
+    public void awaitCompletion(final Conversion... conversions)
+    {
+        awaitCompletion(conversionMonitor, conversions);
+    }
+
+    @Override
+    public void monitor(final Conversion... conversions)
+    {
+        monitor(conversionMonitor, conversions);
+    }
+
+    @Override
+    public void awaitCompletion(final Long maxWait, final TimeUnit timeUnit,
+        final Conversion... conversions)
+    {
+        awaitCompletion(maxWait, timeUnit, conversionMonitor, conversions);
+    }
+
+    @Override
+    public void monitor(final Long maxWait, final TimeUnit timeUnit,
+        final Conversion... conversions)
+    {
+        monitor(maxWait, timeUnit, conversionMonitor, conversions);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseVirtualApplianceMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseVirtualApplianceMonitor.java
new file mode 100644
index 0000000..a1948dc
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseVirtualApplianceMonitor.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.Constants.PROPERTY_SCHEDULER_THREADS;
+import static org.jclouds.abiquo.config.AbiquoProperties.ASYNC_TASK_MONITOR_DELAY;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.internal.BaseMonitoringService;
+import org.jclouds.abiquo.monitor.VirtualApplianceMonitor;
+import org.jclouds.abiquo.monitor.functions.VirtualApplianceDeployMonitor;
+import org.jclouds.abiquo.monitor.functions.VirtualApplianceUndeployMonitor;
+import org.jclouds.rest.RestContext;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.eventbus.EventBus;
+
+/**
+ * Default monitor for {@link VirtualAppliance} objects.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BaseVirtualApplianceMonitor extends BaseMonitoringService implements
+    VirtualApplianceMonitor
+{
+    @VisibleForTesting
+    protected VirtualApplianceDeployMonitor deployMonitor;
+
+    @VisibleForTesting
+    protected VirtualApplianceUndeployMonitor undeployMonitor;
+
+    @Inject
+    public BaseVirtualApplianceMonitor(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(PROPERTY_SCHEDULER_THREADS) final ScheduledExecutorService scheduler,
+        @Named(ASYNC_TASK_MONITOR_DELAY) final Long pollingDelay, final EventBus eventBus,
+        final VirtualApplianceDeployMonitor deployMonitor,
+        final VirtualApplianceUndeployMonitor undeployMonitor)
+    {
+        super(context, scheduler, pollingDelay, eventBus);
+        this.deployMonitor = checkNotNull(deployMonitor, "deployMonitor");
+        this.undeployMonitor = checkNotNull(undeployMonitor, "undeployMonitor");
+    }
+
+    @Override
+    public void awaitCompletionDeploy(final VirtualAppliance... vapps)
+    {
+        awaitCompletion(deployMonitor, vapps);
+    }
+
+    @Override
+    public void monitorDeploy(final VirtualAppliance... vapps)
+    {
+        monitor(deployMonitor, vapps);
+    }
+
+    @Override
+    public void awaitCompletionDeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualAppliance... vapps)
+    {
+        awaitCompletion(maxWait, timeUnit, deployMonitor, vapps);
+    }
+
+    @Override
+    public void monitorDeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualAppliance... vapps)
+    {
+        monitor(maxWait, timeUnit, deployMonitor, vapps);
+    }
+
+    @Override
+    public void awaitCompletionUndeploy(final VirtualAppliance... vapps)
+    {
+        awaitCompletion(undeployMonitor, vapps);
+    }
+
+    @Override
+    public void monitorUndeploy(final VirtualAppliance... vapps)
+    {
+        monitor(undeployMonitor, vapps);
+    }
+
+    @Override
+    public void awaitCompletionUndeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualAppliance... vapps)
+    {
+        awaitCompletion(maxWait, timeUnit, undeployMonitor, vapps);
+    }
+
+    @Override
+    public void monitorUndeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualAppliance... vapps)
+    {
+        monitor(maxWait, timeUnit, undeployMonitor, vapps);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseVirtualMachineMonitor.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseVirtualMachineMonitor.java
new file mode 100644
index 0000000..aa7df18
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseVirtualMachineMonitor.java
@@ -0,0 +1,151 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.Constants.PROPERTY_SCHEDULER_THREADS;
+import static org.jclouds.abiquo.config.AbiquoProperties.ASYNC_TASK_MONITOR_DELAY;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.internal.BaseMonitoringService;
+import org.jclouds.abiquo.monitor.VirtualMachineMonitor;
+import org.jclouds.abiquo.monitor.functions.VirtualMachineDeployMonitor;
+import org.jclouds.abiquo.monitor.functions.VirtualMachineStateMonitor;
+import org.jclouds.abiquo.monitor.functions.VirtualMachineUndeployMonitor;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.eventbus.EventBus;
+
+/**
+ * Default monitor for {@link VirtualMachine} objects.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class BaseVirtualMachineMonitor extends BaseMonitoringService implements
+    VirtualMachineMonitor
+{
+    @VisibleForTesting
+    protected VirtualMachineDeployMonitor deployMonitor;
+
+    @VisibleForTesting
+    protected VirtualMachineUndeployMonitor undeployMonitor;
+
+    @Inject
+    public BaseVirtualMachineMonitor(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(PROPERTY_SCHEDULER_THREADS) final ScheduledExecutorService scheduler,
+        @Named(ASYNC_TASK_MONITOR_DELAY) final Long pollingDelay, final EventBus eventBus,
+        final VirtualMachineDeployMonitor deployMonitor,
+        final VirtualMachineUndeployMonitor undeployMonitor)
+    {
+        super(context, scheduler, pollingDelay, eventBus);
+        this.deployMonitor = checkNotNull(deployMonitor, "deployMonitor");
+        this.undeployMonitor = checkNotNull(undeployMonitor, "undeployMonitor");
+    }
+
+    @Override
+    public void awaitCompletionDeploy(final VirtualMachine... vms)
+    {
+        awaitCompletion(deployMonitor, vms);
+    }
+
+    @Override
+    public void monitorDeploy(final VirtualMachine... vms)
+    {
+        monitor(deployMonitor, vms);
+    }
+
+    @Override
+    public void awaitCompletionDeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachine... vms)
+    {
+        awaitCompletion(maxWait, timeUnit, deployMonitor, vms);
+    }
+
+    @Override
+    public void monitorDeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachine... vms)
+    {
+        monitor(maxWait, timeUnit, deployMonitor, vms);
+    }
+
+    @Override
+    public void awaitCompletionUndeploy(final VirtualMachine... vms)
+    {
+        awaitCompletion(undeployMonitor, vms);
+    }
+
+    @Override
+    public void monitorUndeploy(final VirtualMachine... vms)
+    {
+        monitor(undeployMonitor, vms);
+    }
+
+    @Override
+    public void awaitCompletionUndeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachine... vms)
+    {
+        awaitCompletion(maxWait, timeUnit, undeployMonitor, vms);
+    }
+
+    @Override
+    public void monitorUndeploy(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachine... vms)
+    {
+        monitor(maxWait, timeUnit, undeployMonitor, vms);
+    }
+
+    @Override
+    public void awaitState(final VirtualMachineState state, final VirtualMachine... vms)
+    {
+        awaitCompletion(new VirtualMachineStateMonitor(state), vms);
+    }
+
+    @Override
+    public void monitorState(final VirtualMachineState state, final VirtualMachine... vms)
+    {
+        monitor(new VirtualMachineStateMonitor(state), vms);
+    }
+
+    @Override
+    public void awaitState(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachineState state, final VirtualMachine... vms)
+    {
+        awaitCompletion(maxWait, timeUnit, new VirtualMachineStateMonitor(state), vms);
+    }
+
+    @Override
+    public void monitorState(final Long maxWait, final TimeUnit timeUnit,
+        final VirtualMachineState state, final VirtualMachine... vms)
+    {
+        monitor(maxWait, timeUnit, new VirtualMachineStateMonitor(state), vms);
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/ErrorPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/ErrorPredicates.java
new file mode 100644
index 0000000..3300048
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/ErrorPredicates.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy 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.abiquo.predicates;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import com.abiquo.model.transport.error.ErrorDto;
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link ErrorDto} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class ErrorPredicates
+{
+    public static Predicate<ErrorDto> code(final String... codes)
+    {
+        checkNotNull(codes, "codes must be defined");
+
+        return new Predicate<ErrorDto>()
+        {
+            @Override
+            public boolean apply(final ErrorDto error)
+            {
+                return Arrays.asList(codes).contains(error.getCode());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/LinkPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/LinkPredicates.java
new file mode 100644
index 0000000..e10be29
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/LinkPredicates.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import com.abiquo.model.rest.RESTLink;
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link RESTLink} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class LinkPredicates
+{
+    public static Predicate<RESTLink> rel(final String... rels)
+    {
+        checkNotNull(rels, "rels must be defined");
+
+        return new Predicate<RESTLink>()
+        {
+            @Override
+            public boolean apply(final RESTLink link)
+            {
+                return Arrays.asList(rels).contains(link.getRel());
+            }
+        };
+    }
+
+    public static Predicate<RESTLink> isNic()
+    {
+        return new Predicate<RESTLink>()
+        {
+            @Override
+            public boolean apply(final RESTLink link)
+            {
+                return link.getRel().matches("^nic[0-9]+$");
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/ConversionPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/ConversionPredicates.java
new file mode 100644
index 0000000..6959494
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/ConversionPredicates.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.cloud.Conversion;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+
+import com.abiquo.model.enumerator.ConversionState;
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.enumerator.HypervisorType;
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link VirtualMachineTemplate} filters.
+ * 
+ * @author Francesc Montserrat
+ */
+public class ConversionPredicates
+{
+
+    public static Predicate<Conversion> sourceFormat(final DiskFormatType... formats)
+    {
+        checkNotNull(formats, "formats must be defined");
+
+        return new Predicate<Conversion>()
+        {
+            @Override
+            public boolean apply(final Conversion conversion)
+            {
+                return Arrays.asList(formats).contains(conversion.getSourceFormat());
+            }
+        };
+    }
+
+    public static Predicate<Conversion> targetFormat(final DiskFormatType... formats)
+    {
+        checkNotNull(formats, "formats must be defined");
+
+        return new Predicate<Conversion>()
+        {
+            @Override
+            public boolean apply(final Conversion conversion)
+            {
+                return Arrays.asList(formats).contains(conversion.getTargetFormat());
+            }
+        };
+    }
+
+    public static Predicate<Conversion> state(final ConversionState... states)
+    {
+        checkNotNull(states, "states must be defined");
+
+        return new Predicate<Conversion>()
+        {
+            @Override
+            public boolean apply(final Conversion conversion)
+            {
+                return Arrays.asList(states).contains(conversion.getState());
+            }
+        };
+    }
+
+    public static Predicate<Conversion> compatible(final HypervisorType type)
+    {
+        checkNotNull(type, "type must be defined");
+
+        return new Predicate<Conversion>()
+        {
+            @Override
+            public boolean apply(final Conversion conversion)
+            {
+                return type.isCompatible(conversion.getTargetFormat());
+            }
+        };
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualAppliancePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualAppliancePredicates.java
new file mode 100644
index 0000000..426f2f7
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualAppliancePredicates.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link VirtualAppliance} filters.
+ * 
+ * @author Serafín Sedano
+ */
+public class VirtualAppliancePredicates
+{
+    public static Predicate<VirtualAppliance> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<VirtualAppliance>()
+        {
+            @Override
+            public boolean apply(final VirtualAppliance virtualAppliance)
+            {
+                return Arrays.asList(names).contains(virtualAppliance.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualDatacenterPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualDatacenterPredicates.java
new file mode 100644
index 0000000..d515db4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualDatacenterPredicates.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.transform;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.reference.ValidationErrors;
+import org.jclouds.abiquo.reference.rest.ParentLinkName;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Lists;
+
+/**
+ * Container for {@link VirtualDatacenter} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class VirtualDatacenterPredicates
+{
+    public static Predicate<VirtualDatacenter> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<VirtualDatacenter>()
+        {
+            @Override
+            public boolean apply(final VirtualDatacenter virtualDatacenter)
+            {
+                return Arrays.asList(names).contains(virtualDatacenter.getName());
+            }
+        };
+    }
+
+    public static Predicate<VirtualDatacenter> type(final HypervisorType... types)
+    {
+        checkNotNull(types, "types must be defined");
+
+        return new Predicate<VirtualDatacenter>()
+        {
+            @Override
+            public boolean apply(final VirtualDatacenter virtualDatacenter)
+            {
+                return Arrays.asList(types).contains(virtualDatacenter.getHypervisorType());
+            }
+        };
+    }
+
+    public static Predicate<VirtualDatacenter> datacenter(final Datacenter... datacenters)
+    {
+        checkNotNull(datacenters, "datacenters must be defined");
+
+        final List<Integer> ids =
+            Lists.newArrayList(transform(Arrays.asList(datacenters),
+                new Function<Datacenter, Integer>()
+                {
+                    @Override
+                    public Integer apply(final Datacenter input)
+                    {
+                        return input.getId();
+                    }
+                }));
+
+        return new Predicate<VirtualDatacenter>()
+        {
+            @Override
+            public boolean apply(final VirtualDatacenter virtualDatacenter)
+            {
+                // Avoid using the getDatacenter() method since it will generate an unnecessary API
+                // call. We can get the ID from the datacenter link.
+                Integer datacenterId =
+                    checkNotNull(virtualDatacenter.unwrap()
+                        .getIdFromLink(ParentLinkName.DATACENTER),
+                        ValidationErrors.MISSING_REQUIRED_LINK);
+
+                return ids.contains(datacenterId);
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualMachinePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualMachinePredicates.java
new file mode 100644
index 0000000..34ae673
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualMachinePredicates.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link VirtualMachine} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class VirtualMachinePredicates
+{
+    public static Predicate<VirtualMachine> internalName(final String... internalName)
+    {
+        checkNotNull(internalName, "names must be defined");
+
+        return new Predicate<VirtualMachine>()
+        {
+            @Override
+            public boolean apply(final VirtualMachine virtualMachine)
+            {
+                return Arrays.asList(internalName).contains(virtualMachine.getInternalName());
+            }
+        };
+    }
+
+    public static Predicate<VirtualMachine> nameLabel(final String... nameLabels)
+    {
+        checkNotNull(nameLabels, "names must be defined");
+
+        return new Predicate<VirtualMachine>()
+        {
+            @Override
+            public boolean apply(final VirtualMachine virtualMachine)
+            {
+                return Arrays.asList(nameLabels).contains(virtualMachine.getNameLabel());
+            }
+        };
+    }
+
+    public static Predicate<VirtualMachine> state(final VirtualMachineState... states)
+    {
+        checkNotNull(states, "states must be defined");
+
+        return new Predicate<VirtualMachine>()
+        {
+            @Override
+            public boolean apply(final VirtualMachine virtualMachine)
+            {
+                // The getState() method will generate an API call
+                return Arrays.asList(states).contains(virtualMachine.getState());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualMachineTemplatePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualMachineTemplatePredicates.java
new file mode 100644
index 0000000..a90c54e
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VirtualMachineTemplatePredicates.java
@@ -0,0 +1,94 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.enumerator.HypervisorType;
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link VirtualMachineTemplate} filters.
+ * 
+ * @author Francesc Montserrat
+ */
+public class VirtualMachineTemplatePredicates
+{
+    public static Predicate<VirtualMachineTemplate> id(final Integer... ids)
+    {
+        checkNotNull(ids, "ids must be defined");
+
+        return new Predicate<VirtualMachineTemplate>()
+        {
+            @Override
+            public boolean apply(final VirtualMachineTemplate template)
+            {
+                return Arrays.asList(ids).contains(template.getId());
+            }
+        };
+    }
+
+    public static Predicate<VirtualMachineTemplate> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<VirtualMachineTemplate>()
+        {
+            @Override
+            public boolean apply(final VirtualMachineTemplate template)
+            {
+                return Arrays.asList(names).contains(template.getName());
+            }
+        };
+    }
+
+    public static Predicate<VirtualMachineTemplate> diskFormat(final DiskFormatType... formats)
+    {
+        checkNotNull(formats, "formats must be defined");
+
+        return new Predicate<VirtualMachineTemplate>()
+        {
+            @Override
+            public boolean apply(final VirtualMachineTemplate template)
+            {
+                return Arrays.asList(formats).contains(template.getDiskFormatType());
+            }
+        };
+    }
+
+    public static Predicate<VirtualMachineTemplate> compatible(final HypervisorType type)
+    {
+        checkNotNull(type, "type must be defined");
+
+        return new Predicate<VirtualMachineTemplate>()
+        {
+            @Override
+            public boolean apply(final VirtualMachineTemplate template)
+            {
+                return type.isCompatible(template.getDiskFormatType());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VolumePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VolumePredicates.java
new file mode 100644
index 0000000..b85ef9f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/cloud/VolumePredicates.java
@@ -0,0 +1,89 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.cloud;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.cloud.Volume;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+
+/**
+ * Container for {@link Volume} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class VolumePredicates
+{
+    public static Predicate<Volume> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Volume>()
+        {
+            @Override
+            public boolean apply(final Volume volume)
+            {
+                return Arrays.asList(names).contains(volume.getName());
+            }
+        };
+    }
+
+    public static Predicate<Volume> greaterThan(final long sizeInMb)
+    {
+        checkNotNull(sizeInMb, "sizeInMb must be defined");
+
+        return new Predicate<Volume>()
+        {
+            @Override
+            public boolean apply(final Volume volume)
+            {
+                return volume.getSizeInMB() > sizeInMb;
+            }
+        };
+    }
+
+    public static Predicate<Volume> greaterThanOrEqual(final long sizeInMb)
+    {
+        checkNotNull(sizeInMb, "sizeInMb must be defined");
+
+        return new Predicate<Volume>()
+        {
+            @Override
+            public boolean apply(final Volume volume)
+            {
+                return volume.getSizeInMB() >= sizeInMb;
+            }
+        };
+    }
+
+    public static Predicate<Volume> lesserThan(final long sizeInMb)
+    {
+        return Predicates.not(greaterThanOrEqual(sizeInMb));
+    }
+
+    public static Predicate<Volume> lesserThanOrEquals(final long sizeInMb)
+    {
+        return Predicates.not(greaterThan(sizeInMb));
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/CategoryPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/CategoryPredicates.java
new file mode 100644
index 0000000..04bed94
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/CategoryPredicates.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.config;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.config.Category;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Category} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class CategoryPredicates
+{
+    public static Predicate<Category> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Category>()
+        {
+            @Override
+            public boolean apply(final Category category)
+            {
+                return Arrays.asList(names).contains(category.getName());
+            }
+        };
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/CurrencyPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/CurrencyPredicates.java
new file mode 100644
index 0000000..4261dfb
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/CurrencyPredicates.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.config;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.config.Currency;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Currency} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ */
+public class CurrencyPredicates
+{
+    public static Predicate<Currency> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Currency>()
+        {
+            @Override
+            public boolean apply(final Currency currency)
+            {
+                return Arrays.asList(names).contains(currency.getName());
+            }
+        };
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/LicensePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/LicensePredicates.java
new file mode 100644
index 0000000..d99705f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/LicensePredicates.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.config;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.config.License;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link License} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class LicensePredicates
+{
+    public static Predicate<License> customer(final String... customerIds)
+    {
+        checkNotNull(customerIds, "customers must be defined");
+
+        return new Predicate<License>()
+        {
+            @Override
+            public boolean apply(final License license)
+            {
+                return Arrays.asList(customerIds).contains(license.getCustomerId());
+            }
+        };
+    }
+
+    public static Predicate<License> code(final String... codes)
+    {
+        checkNotNull(codes, "customers must be defined");
+
+        return new Predicate<License>()
+        {
+            @Override
+            public boolean apply(final License license)
+            {
+                return Arrays.asList(codes).contains(license.getCode());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/PrivilegePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/PrivilegePredicates.java
new file mode 100644
index 0000000..20f9ca8
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/PrivilegePredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.config;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.config.Privilege;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Privilege} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class PrivilegePredicates
+{
+    public static Predicate<Privilege> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Privilege>()
+        {
+            @Override
+            public boolean apply(final Privilege privilege)
+            {
+                return Arrays.asList(names).contains(privilege.getName());
+            }
+        };
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/SystemPropertyPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/SystemPropertyPredicates.java
new file mode 100644
index 0000000..b5fc62d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/config/SystemPropertyPredicates.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.config;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.config.SystemProperty;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link SystemProperty} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class SystemPropertyPredicates
+{
+    public static Predicate<SystemProperty> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<SystemProperty>()
+        {
+            @Override
+            public boolean apply(final SystemProperty property)
+            {
+                return Arrays.asList(names).contains(property.getName());
+            }
+        };
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/EnterprisePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/EnterprisePredicates.java
new file mode 100644
index 0000000..c411e82
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/EnterprisePredicates.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.enterprise;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Enterprise} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class EnterprisePredicates
+{
+    public static Predicate<Enterprise> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Enterprise>()
+        {
+            @Override
+            public boolean apply(final Enterprise enterprise)
+            {
+                return Arrays.asList(names).contains(enterprise.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/RolePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/RolePredicates.java
new file mode 100644
index 0000000..1cd895c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/RolePredicates.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.enterprise;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.enterprise.Role;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Role} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class RolePredicates
+{
+    public static Predicate<Role> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Role>()
+        {
+            @Override
+            public boolean apply(final Role role)
+            {
+                return Arrays.asList(names).contains(role.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/TemplateDefinitionListPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/TemplateDefinitionListPredicates.java
new file mode 100644
index 0000000..1039d89
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/TemplateDefinitionListPredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.enterprise;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.enterprise.TemplateDefinitionList;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link TemplateDefinitionList} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class TemplateDefinitionListPredicates
+{
+    public static Predicate<TemplateDefinitionList> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<TemplateDefinitionList>()
+        {
+            @Override
+            public boolean apply(final TemplateDefinitionList templateList)
+            {
+                return Arrays.asList(names).contains(templateList.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/UserPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/UserPredicates.java
new file mode 100644
index 0000000..8a3823f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/enterprise/UserPredicates.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.enterprise;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.enterprise.User;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link User} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class UserPredicates
+{
+    public static Predicate<User> nick(final String... nicks)
+    {
+        checkNotNull(nicks, "nicks must be defined");
+
+        return new Predicate<User>()
+        {
+            @Override
+            public boolean apply(final User user)
+            {
+                return Arrays.asList(nicks).contains(user.getNick());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/BladePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/BladePredicates.java
new file mode 100644
index 0000000..304ed26
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/BladePredicates.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.Blade;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Blade} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class BladePredicates
+{
+    public static Predicate<Blade> name(final String... names)
+    {
+        checkNotNull(names, "name must be defined");
+
+        return new Predicate<Blade>()
+        {
+            @Override
+            public boolean apply(final Blade machine)
+            {
+                return Arrays.asList(names).contains(machine.getName());
+            }
+        };
+    }
+
+    public static Predicate<Blade> ip(final String ip)
+    {
+        return ips(checkNotNull(ip, "ip must be defined"));
+    }
+
+    public static Predicate<Blade> ips(final String... ips)
+    {
+        checkNotNull(ips, "ips must be defined");
+
+        return new Predicate<Blade>()
+        {
+            @Override
+            public boolean apply(final Blade machine)
+            {
+                return Arrays.asList(ips).contains(machine.getIp());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/DatacenterPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/DatacenterPredicates.java
new file mode 100644
index 0000000..d3febc3
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/DatacenterPredicates.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Datacenter} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class DatacenterPredicates
+{
+    public static Predicate<Datacenter> id(final Integer... ids)
+    {
+        checkNotNull(ids, "ids must be defined");
+
+        return new Predicate<Datacenter>()
+        {
+            @Override
+            public boolean apply(final Datacenter datacenter)
+            {
+                return Arrays.asList(ids).contains(datacenter.getId());
+            }
+        };
+    }
+
+    public static Predicate<Datacenter> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Datacenter>()
+        {
+            @Override
+            public boolean apply(final Datacenter datacenter)
+            {
+                return Arrays.asList(names).contains(datacenter.getName());
+            }
+        };
+    }
+
+    public static Predicate<Datacenter> location(final String... locations)
+    {
+        checkNotNull(locations, "locations must be defined");
+
+        return new Predicate<Datacenter>()
+        {
+            @Override
+            public boolean apply(final Datacenter datacenter)
+            {
+                return Arrays.asList(locations).contains(datacenter.getLocation());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/DatastorePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/DatastorePredicates.java
new file mode 100644
index 0000000..d094594
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/DatastorePredicates.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.Datastore;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Datastore} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class DatastorePredicates
+{
+    public static Predicate<Datastore> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Datastore>()
+        {
+            @Override
+            public boolean apply(final Datastore datastore)
+            {
+                return Arrays.asList(names).contains(datastore.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/HypervisorPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/HypervisorPredicates.java
new file mode 100644
index 0000000..09ad31f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/HypervisorPredicates.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link HypervisorType} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class HypervisorPredicates
+{
+    public static Predicate<HypervisorType> type(final HypervisorType... types)
+    {
+        checkNotNull(types, "types must be defined");
+
+        return new Predicate<HypervisorType>()
+        {
+            @Override
+            public boolean apply(final HypervisorType type)
+            {
+                return Arrays.asList(types).contains(type);
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/LogicServerPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/LogicServerPredicates.java
new file mode 100644
index 0000000..4ec5bc2
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/LogicServerPredicates.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.LogicServer;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link LogicServer} filters.
+ * 
+ * @author Francesc Montserrat
+ */
+public class LogicServerPredicates
+{
+    public static Predicate<LogicServer> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<LogicServer>()
+        {
+            @Override
+            public boolean apply(final LogicServer logicServer)
+            {
+                return Arrays.asList(names).contains(logicServer.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/MachinePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/MachinePredicates.java
new file mode 100644
index 0000000..8857f8a
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/MachinePredicates.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Machine} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class MachinePredicates
+{
+    public static Predicate<Machine> name(final String... names)
+    {
+        checkNotNull(names, "name must be defined");
+
+        return new Predicate<Machine>()
+        {
+            @Override
+            public boolean apply(final Machine machine)
+            {
+                return Arrays.asList(names).contains(machine.getName());
+            }
+        };
+    }
+
+    public static Predicate<Machine> ip(final String ip)
+    {
+        return ips(checkNotNull(ip, "ip must be defined"));
+    }
+
+    public static Predicate<Machine> ips(final String... ips)
+    {
+        checkNotNull(ips, "ips must be defined");
+
+        return new Predicate<Machine>()
+        {
+            @Override
+            public boolean apply(final Machine machine)
+            {
+                return Arrays.asList(ips).contains(machine.getIp());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/ManagedRackPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/ManagedRackPredicates.java
new file mode 100644
index 0000000..fcd5401
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/ManagedRackPredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.ManagedRack;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link ManagedRack} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class ManagedRackPredicates
+{
+    public static Predicate<ManagedRack> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<ManagedRack>()
+        {
+            @Override
+            public boolean apply(final ManagedRack rack)
+            {
+                return Arrays.asList(names).contains(rack.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/RackPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/RackPredicates.java
new file mode 100644
index 0000000..d2ed7de
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/RackPredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.Rack;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Rack} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class RackPredicates
+{
+    public static Predicate<Rack> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Rack>()
+        {
+            @Override
+            public boolean apply(final Rack rack)
+            {
+                return Arrays.asList(names).contains(rack.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/RemoteServicePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/RemoteServicePredicates.java
new file mode 100644
index 0000000..64b7c40
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/RemoteServicePredicates.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.RemoteService;
+
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link RemoteService} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class RemoteServicePredicates
+{
+    public static Predicate<RemoteService> type(final RemoteServiceType... types)
+    {
+        checkNotNull(types, "types must be defined");
+
+        return new Predicate<RemoteService>()
+        {
+            @Override
+            public boolean apply(final RemoteService remoteService)
+            {
+                return Arrays.asList(types).contains(remoteService.getType());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StorageDeviceMetadataPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StorageDeviceMetadataPredicates.java
new file mode 100644
index 0000000..e4971f0
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StorageDeviceMetadataPredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.StorageDeviceMetadata;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link StorageDeviceMetadata} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class StorageDeviceMetadataPredicates
+{
+
+    public static Predicate<StorageDeviceMetadata> type(final String... types)
+    {
+        checkNotNull(types, "types must be defined");
+
+        return new Predicate<StorageDeviceMetadata>()
+        {
+            @Override
+            public boolean apply(final StorageDeviceMetadata metadata)
+            {
+                return Arrays.asList(types).contains(metadata.getType());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StorageDevicePredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StorageDevicePredicates.java
new file mode 100644
index 0000000..1a0e6a2
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StorageDevicePredicates.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.StorageDevice;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link StorageDevice} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class StorageDevicePredicates
+{
+    public static Predicate<StorageDevice> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<StorageDevice>()
+        {
+            @Override
+            public boolean apply(final StorageDevice storageDevice)
+            {
+                return Arrays.asList(names).contains(storageDevice.getName());
+            }
+        };
+    }
+
+    public static Predicate<StorageDevice> managementIp(final String... ips)
+    {
+        checkNotNull(ips, "managementIps must be defined");
+
+        return new Predicate<StorageDevice>()
+        {
+            @Override
+            public boolean apply(final StorageDevice storageDevice)
+            {
+                return Arrays.asList(ips).contains(storageDevice.getManagementIp());
+            }
+        };
+    }
+
+    public static Predicate<StorageDevice> type(final String... types)
+    {
+        checkNotNull(types, "types must be defined");
+
+        return new Predicate<StorageDevice>()
+        {
+            @Override
+            public boolean apply(final StorageDevice storageDevice)
+            {
+                return Arrays.asList(types).contains(storageDevice.getType());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StoragePoolPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StoragePoolPredicates.java
new file mode 100644
index 0000000..5363664
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/StoragePoolPredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.StoragePool;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link StoragePool} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class StoragePoolPredicates
+{
+    public static Predicate<StoragePool> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<StoragePool>()
+        {
+            @Override
+            public boolean apply(final StoragePool storagePool)
+            {
+                return Arrays.asList(names).contains(storagePool.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/TierPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/TierPredicates.java
new file mode 100644
index 0000000..66414ce
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/infrastructure/TierPredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.infrastructure;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.infrastructure.Tier;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Tier} filters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class TierPredicates
+{
+    public static Predicate<Tier> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Tier>()
+        {
+            @Override
+            public boolean apply(final Tier tier)
+            {
+                return Arrays.asList(names).contains(tier.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/IpPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/IpPredicates.java
new file mode 100644
index 0000000..b05947c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/IpPredicates.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.network.AbstractPublicIp;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.Network;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Network} filters.
+ * 
+ * @author Francesc Montserrat
+ */
+public class IpPredicates
+{
+    public static <T extends Ip< ? , ? >> Predicate<T> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<T>()
+        {
+            @Override
+            public boolean apply(final T address)
+            {
+                return Arrays.asList(names).contains(address.getName());
+            }
+        };
+    }
+
+    public static <T extends Ip< ? , ? >> Predicate<T> address(final String... addresses)
+    {
+        checkNotNull(addresses, "addresses must be defined");
+
+        return new Predicate<T>()
+        {
+            @Override
+            public boolean apply(final T address)
+            {
+                return Arrays.asList(addresses).contains(address.getIp());
+            }
+        };
+    }
+
+    public static <T extends AbstractPublicIp< ? , ? >> Predicate<T> available()
+    {
+        return new Predicate<T>()
+        {
+            @Override
+            public boolean apply(final T address)
+            {
+                return address.isAvailable();
+            }
+        };
+    }
+
+    public static <T extends Ip< ? , ? >> Predicate<T> notUsed()
+    {
+        return new Predicate<T>()
+        {
+            @Override
+            public boolean apply(final T address)
+            {
+                return address.unwrap().searchLink("virtualmachine") == null;
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/NetworkPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/NetworkPredicates.java
new file mode 100644
index 0000000..eb22fdb
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/NetworkPredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.Network;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Network} filters.
+ * 
+ * @author Francesc Montserrat
+ */
+public class NetworkPredicates
+{
+    public static <T extends Ip< ? , ? >> Predicate<Network<T>> name(final String... names)
+    {
+        checkNotNull(names, "names must be defined");
+
+        return new Predicate<Network<T>>()
+        {
+            @Override
+            public boolean apply(final Network<T> network)
+            {
+                return Arrays.asList(names).contains(network.getName());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/NicPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/NicPredicates.java
new file mode 100644
index 0000000..6df89c4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/network/NicPredicates.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.network;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.network.Nic;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link Nic} filters.
+ * 
+ * @author Francesc Montserrat
+ */
+public class NicPredicates
+{
+    public static Predicate<Nic> ip(final String... ips)
+    {
+        checkNotNull(ips, "ips must be defined");
+
+        return new Predicate<Nic>()
+        {
+            @Override
+            public boolean apply(final Nic nic)
+            {
+                return Arrays.asList(ips).contains(nic.getIp());
+            }
+        };
+    }
+
+    public static Predicate<Nic> mac(final String... macs)
+    {
+        checkNotNull(macs, "macs must be defined");
+
+        return new Predicate<Nic>()
+        {
+            @Override
+            public boolean apply(final Nic nic)
+            {
+                return Arrays.asList(macs).contains(nic.getMac());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/task/AsyncTaskPredicates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/task/AsyncTaskPredicates.java
new file mode 100644
index 0000000..7f0f685
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/predicates/task/AsyncTaskPredicates.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.predicates.task;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Arrays;
+
+import org.jclouds.abiquo.domain.task.AsyncTask;
+
+import com.abiquo.server.core.task.enums.TaskState;
+import com.google.common.base.Predicate;
+
+/**
+ * Container for {@link AsyncTask} filters.
+ * 
+ * @author Ignasi Barrera
+ */
+public class AsyncTaskPredicates
+{
+    public static Predicate<AsyncTask> state(final TaskState... states)
+    {
+        checkNotNull(states, "states must be defined");
+
+        return new Predicate<AsyncTask>()
+        {
+            @Override
+            public boolean apply(final AsyncTask task)
+            {
+                return Arrays.asList(states).contains(task.getState());
+            }
+        };
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/ValidationErrors.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/ValidationErrors.java
new file mode 100644
index 0000000..1f3ce1c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/ValidationErrors.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.reference;
+
+/**
+ * Error constants.
+ * 
+ * @author Francesc Montserrat
+ */
+public class ValidationErrors
+{
+    public static final String NULL_RESOURCE = "The resource should be assigned to a ";
+
+    public static final String MISSING_REQUIRED_FIELD = "Missing required field ";
+
+    public static final String MISSING_REQUIRED_LINK = "Missing required link ";
+
+    public static final String INVALID_NETWORK_TYPE = "Invalid network type ";
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/annotations/EnterpriseEdition.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/annotations/EnterpriseEdition.java
new file mode 100644
index 0000000..9862629
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/annotations/EnterpriseEdition.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.reference.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Indicates that the annotated element will access Abiquo Enterprise Edition functionallity. If the
+ * target Abiquo Cloud platform is a Community Edition version, the invocation of the method may
+ * have unexpected results.
+ * 
+ * @author Ignasi Barrera
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnterpriseEdition
+{
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/rest/ParentLinkName.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/rest/ParentLinkName.java
new file mode 100644
index 0000000..9db695a
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/reference/rest/ParentLinkName.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.reference.rest;
+
+/**
+ * Names of the "rel" attribute of the links that point to parent objects.
+ * 
+ * @author Francesc Montserrat
+ */
+public class ParentLinkName
+{
+    public final static String RACK = "rack";
+
+    public final static String DATACENTER = "datacenter";
+
+    public final static String ENTERPRISE = "enterprise";
+
+    public final static String ROLE = "role";
+
+    public final static String TIER = "tier";
+
+    public final static String STORAGE_DEVICE = "device";
+
+    public final static String VIRTUAL_DATACENTER = "virtualdatacenter";
+
+    public final static String VIRTUAL_APPLIANCE = "virtualappliance";
+
+    public final static String VIRTUAL_MACHINE_TEMPLATE = "virtualmachinetemplate";
+
+    public final static String DATACENTER_REPOSITORY = "datacenterrepository";
+
+    public final static String COST_CODE = "costcode";
+
+    public final static String CATEGORY = "category";
+
+    public final static String ICON = "icon";
+
+    public final static String PRIVATE_NETWORK = "privatenetwork";
+
+    public final static String PUBLIC_NETWORK = "publicnetwork";
+
+    public final static String EXTERNAL_NETWORK = "externalnetwork";
+
+    public final static String UNMANAGED_NETWORK = "unmanagednetwork";
+
+    public final static String NETWORK_CONFIGURATIONS = "configurations";
+
+    public final static String NETWORK_GATEWAY = "network_configuration";
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/annotations/EndpointLink.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/annotations/EndpointLink.java
new file mode 100644
index 0000000..f32d6b0
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/annotations/EndpointLink.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.rest.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Indicates the link to be used to generate the enpoind for the request.
+ * 
+ * @author Ignasi Barrera
+ */
+@Target({ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EndpointLink
+{
+
+    /**
+     * The name of the link that will be used to generate the request endpoint.
+     */
+    String value();
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/AbiquoHttpAsyncClient.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/AbiquoHttpAsyncClient.java
new file mode 100644
index 0000000..6ffd12a
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/AbiquoHttpAsyncClient.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.rest.internal;
+
+import javax.ws.rs.GET;
+
+import org.jclouds.abiquo.binders.BindLinkToPathAndAcceptHeader;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.abiquo.model.rest.RESTLink;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Custom Rest methods to work with the Abiquo Api.
+ * 
+ * @author Ignasi Barrera
+ */
+@RequestFilters({AbiquoAuthentication.class, AppendApiVersionToMediaType.class})
+public interface AbiquoHttpAsyncClient
+{
+    /**
+     * @see AbiquoHttpClient#get(RESTLink)
+     */
+    @GET
+    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+    public ListenableFuture<HttpResponse> get(
+        @BinderParam(BindLinkToPathAndAcceptHeader.class) final RESTLink link);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/AbiquoHttpClient.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/AbiquoHttpClient.java
new file mode 100644
index 0000000..1e51824
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/AbiquoHttpClient.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.rest.internal;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.http.HttpResponse;
+
+import com.abiquo.model.rest.RESTLink;
+
+/**
+ * Custom Rest methods to work with the Abiquo Api.
+ * 
+ * @author Ignasi Barrera
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface AbiquoHttpClient
+{
+    /**
+     * Perform a GET request to the given link.
+     * 
+     * @param link The link to get.
+     * @return The response.
+     */
+    public HttpResponse get(final RESTLink link);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/ExtendedUtils.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/ExtendedUtils.java
new file mode 100644
index 0000000..13b9551
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/rest/internal/ExtendedUtils.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.rest.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jclouds.Constants;
+import org.jclouds.crypto.Crypto;
+import org.jclouds.date.DateService;
+import org.jclouds.domain.Credentials;
+import org.jclouds.json.Json;
+import org.jclouds.logging.Logger.LoggerFactory;
+import org.jclouds.rest.HttpAsyncClient;
+import org.jclouds.rest.HttpClient;
+import org.jclouds.rest.Utils;
+import org.jclouds.rest.internal.UtilsImpl;
+import org.jclouds.xml.XMLParser;
+
+import com.google.common.eventbus.EventBus;
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+
+/**
+ * Custom utility methods.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ExtendedUtils extends UtilsImpl implements Utils
+{
+    private AbiquoHttpClient abiquoHttpClient;
+
+    private AbiquoHttpAsyncClient abiquoHttpAsyncApi;
+
+    @Inject
+    public ExtendedUtils(final Injector injector, final Json json, final XMLParser xml,
+        final HttpClient simpleApi, final HttpAsyncClient simpleAsyncApi, final Crypto encryption,
+        final DateService date,
+        @Named(Constants.PROPERTY_USER_THREADS) final ExecutorService userThreads,
+        @Named(Constants.PROPERTY_IO_WORKER_THREADS) final ExecutorService ioThreads,
+        final EventBus eventBus, final Map<String, Credentials> credentialStore,
+        final LoggerFactory loggerFactory, final AbiquoHttpClient abiquoHttpClient,
+        final AbiquoHttpAsyncClient abiquoHttpAsyncApi)
+    {
+        super(injector, json, xml, simpleApi, simpleAsyncApi, encryption, date, userThreads,
+            ioThreads, eventBus, credentialStore, loggerFactory);
+        this.abiquoHttpClient = checkNotNull(abiquoHttpClient, "abiquoHttpClient");
+        this.abiquoHttpAsyncApi = checkNotNull(abiquoHttpAsyncApi, "abiquoHttpAsyncApi");
+    }
+
+    public AbiquoHttpClient getAbiquoHttpClient()
+    {
+        return abiquoHttpClient;
+    }
+
+    public AbiquoHttpAsyncClient getAbiquoHttpAsyncClient()
+    {
+        return abiquoHttpAsyncApi;
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/ListEntities.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/ListEntities.java
new file mode 100644
index 0000000..16febd2
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/ListEntities.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy;
+
+import org.jclouds.abiquo.domain.DomainWrapper;
+
+import com.google.common.base.Predicate;
+
+/**
+ * List all entities of the given type.
+ * 
+ * @author Ignasi Barrera
+ */
+public interface ListEntities<T extends DomainWrapper< ? >, P extends DomainWrapper< ? >>
+{
+    Iterable<T> execute(P parent);
+
+    Iterable<T> execute(P parent, Predicate<T> selector);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/ListRootEntities.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/ListRootEntities.java
new file mode 100644
index 0000000..5d05902
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/ListRootEntities.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy;
+
+import org.jclouds.abiquo.domain.DomainWrapper;
+
+import com.google.common.base.Predicate;
+
+/**
+ * List all entities of the given type.
+ * 
+ * @author Ignasi Barrera
+ */
+public interface ListRootEntities<T extends DomainWrapper< ? >>
+{
+    Iterable<T> execute();
+
+    Iterable<T> execute(Predicate<T> selector);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/admin/ListRoles.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/admin/ListRoles.java
new file mode 100644
index 0000000..f6922de
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/admin/ListRoles.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.admin;
+
+import org.jclouds.abiquo.domain.enterprise.Role;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.admin.internal.ListRolesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List roles.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListRolesImpl.class)
+public interface ListRoles extends ListRootEntities<Role>
+{
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/admin/internal/ListRolesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/admin/internal/ListRolesImpl.java
new file mode 100644
index 0000000..8111348
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/admin/internal/ListRolesImpl.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.admin.internal;
+
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.enterprise.Role;
+import org.jclouds.abiquo.strategy.admin.ListRoles;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.RolesDto;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List enterprises.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ListRolesImpl implements ListRoles
+{
+    // This strategy does not have still an Executor instance because the current methods call
+    // single api methods
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    ListRolesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public Iterable<Role> execute()
+    {
+        RolesDto result = context.getApi().getAdminApi().listRoles();
+        return wrap(context, Role.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<Role> execute(final Predicate<Role> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListAttachedNics.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListAttachedNics.java
new file mode 100644
index 0000000..97e751b
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListAttachedNics.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.strategy.ListEntities;
+import org.jclouds.abiquo.strategy.cloud.internal.ListAttachedNicsImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List all NICs attached to a given virtual machine.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListAttachedNicsImpl.class)
+public interface ListAttachedNics extends ListEntities<Ip< ? , ? >, VirtualMachine>
+{
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualAppliances.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualAppliances.java
new file mode 100644
index 0000000..10a9c5a
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualAppliances.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud;
+
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.cloud.internal.ListVirtualAppliancesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List virtual appliances in each virtual datacenter.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListVirtualAppliancesImpl.class)
+public interface ListVirtualAppliances extends ListRootEntities<VirtualAppliance>
+{
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualDatacenters.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualDatacenters.java
new file mode 100644
index 0000000..7f2b7b0
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualDatacenters.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud;
+
+import java.util.List;
+
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.options.VirtualDatacenterOptions;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.cloud.internal.ListVirtualDatacentersImpl;
+
+import com.google.common.base.Predicate;
+import com.google.inject.ImplementedBy;
+
+/**
+ * List virtual datacenters.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListVirtualDatacentersImpl.class)
+public interface ListVirtualDatacenters extends ListRootEntities<VirtualDatacenter>
+{
+    Iterable<VirtualDatacenter> execute(VirtualDatacenterOptions virtualDatacenterOptions);
+
+    Iterable<VirtualDatacenter> execute(List<Integer> virtualDatacenterIds);
+
+    Iterable<VirtualDatacenter> execute(Predicate<VirtualDatacenter> selector,
+        VirtualDatacenterOptions virtualDatacenterOptions);
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualMachines.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualMachines.java
new file mode 100644
index 0000000..ba6f386
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/ListVirtualMachines.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineOptions;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.cloud.internal.ListVirtualMachinesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List virtual machines in each virtual datacenter and each virtual appliance.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListVirtualMachinesImpl.class)
+public interface ListVirtualMachines extends ListRootEntities<VirtualMachine>
+{
+    Iterable<VirtualMachine> execute(VirtualMachineOptions options);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListAttachedNicsImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListAttachedNicsImpl.java
new file mode 100644
index 0000000..cf3c16c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListAttachedNicsImpl.java
@@ -0,0 +1,138 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.transform;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.network.ExternalIp;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PublicIp;
+import org.jclouds.abiquo.domain.network.UnmanagedIp;
+import org.jclouds.abiquo.domain.util.LinkUtils;
+import org.jclouds.abiquo.rest.internal.ExtendedUtils;
+import org.jclouds.abiquo.strategy.cloud.ListAttachedNics;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.network.ExternalIpDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpDto;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+/**
+ * List all NICs attached to a given virtual machine.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ListAttachedNicsImpl implements ListAttachedNics
+{
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    protected final ExtendedUtils extendedUtils;
+
+    @Inject
+    public ListAttachedNicsImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        final ExtendedUtils extendedUtils)
+    {
+        this.context = checkNotNull(context, "context");
+        this.extendedUtils = checkNotNull(extendedUtils, "extendedUtils");
+    }
+
+    @Override
+    public Iterable<Ip< ? , ? >> execute(final VirtualMachine parent)
+    {
+        parent.refresh();
+        Iterable<RESTLink> nicLinks = LinkUtils.filterNicLinks(parent.unwrap().getLinks());
+        return listIps(nicLinks);
+    }
+
+    @Override
+    public Iterable<Ip< ? , ? >> execute(final VirtualMachine parent,
+        final Predicate<Ip< ? , ? >> selector)
+    {
+        return filter(execute(parent), selector);
+    }
+
+    private Iterable<Ip< ? , ? >> listIps(final Iterable<RESTLink> nicLinks)
+    {
+        return transform(nicLinks, new Function<RESTLink, Ip< ? , ? >>()
+        {
+            @Override
+            public Ip< ? , ? > apply(final RESTLink input)
+            {
+                HttpResponse response = extendedUtils.getAbiquoHttpClient().get(input);
+
+                if (input.getType().equals(PrivateIpDto.BASE_MEDIA_TYPE))
+                {
+                    ParseXMLWithJAXB<PrivateIpDto> parser =
+                        new ParseXMLWithJAXB<PrivateIpDto>(extendedUtils.getXml(), TypeLiteral
+                            .get(PrivateIpDto.class));
+
+                    return wrap(context, PrivateIp.class, parser.apply(response));
+                }
+                else if (input.getType().equals(PublicIpDto.BASE_MEDIA_TYPE))
+                {
+                    ParseXMLWithJAXB<PublicIpDto> parser =
+                        new ParseXMLWithJAXB<PublicIpDto>(extendedUtils.getXml(), TypeLiteral
+                            .get(PublicIpDto.class));
+
+                    return wrap(context, PublicIp.class, parser.apply(response));
+                }
+                else if (input.getType().equals(ExternalIpDto.BASE_MEDIA_TYPE))
+                {
+                    ParseXMLWithJAXB<ExternalIpDto> parser =
+                        new ParseXMLWithJAXB<ExternalIpDto>(extendedUtils.getXml(), TypeLiteral
+                            .get(ExternalIpDto.class));
+
+                    return wrap(context, ExternalIp.class, parser.apply(response));
+                }
+                else if (input.getType().equals(UnmanagedIpDto.BASE_MEDIA_TYPE))
+                {
+                    ParseXMLWithJAXB<UnmanagedIpDto> parser =
+                        new ParseXMLWithJAXB<UnmanagedIpDto>(extendedUtils.getXml(), TypeLiteral
+                            .get(UnmanagedIpDto.class));
+
+                    return wrap(context, UnmanagedIp.class, parser.apply(response));
+                }
+                else
+                {
+                    throw new IllegalArgumentException("Unsupported media type: " + input.getType());
+                }
+            }
+        });
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualAppliancesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualAppliancesImpl.java
new file mode 100644
index 0000000..7c70d3a
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualAppliancesImpl.java
@@ -0,0 +1,117 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.jclouds.concurrent.FutureIterables.transformParallel;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualAppliances;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualDatacenters;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List virtual appliance in each virtual datacenter.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ListVirtualAppliancesImpl implements ListVirtualAppliances
+{
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    protected final ListVirtualDatacenters listVirtualDatacenters;
+
+    protected final ExecutorService userExecutor;
+
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Inject(optional = true)
+    @Named(Constants.PROPERTY_REQUEST_TIMEOUT)
+    protected Long maxTime;
+
+    @Inject
+    ListVirtualAppliancesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(Constants.PROPERTY_USER_THREADS) final ExecutorService userExecutor,
+        final ListVirtualDatacenters listVirtualDatacenters)
+    {
+        this.context = checkNotNull(context, "context");
+        this.listVirtualDatacenters =
+            checkNotNull(listVirtualDatacenters, "listVirtualDatacenters");
+        this.userExecutor = checkNotNull(userExecutor, "userExecutor");
+    }
+
+    @Override
+    public Iterable<VirtualAppliance> execute()
+    {
+        // Find virtual appliances in concurrent requests
+        Iterable<VirtualDatacenter> vdcs = listVirtualDatacenters.execute();
+        Iterable<VirtualApplianceDto> vapps = listConcurrentVirtualAppliances(vdcs);
+
+        return wrap(context, VirtualAppliance.class, vapps);
+    }
+
+    @Override
+    public Iterable<VirtualAppliance> execute(final Predicate<VirtualAppliance> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+    private Iterable<VirtualApplianceDto> listConcurrentVirtualAppliances(
+        final Iterable<VirtualDatacenter> vdcs)
+    {
+        Iterable<VirtualAppliancesDto> vapps =
+            transformParallel(vdcs,
+                new Function<VirtualDatacenter, Future< ? extends VirtualAppliancesDto>>()
+                {
+                    @Override
+                    public Future<VirtualAppliancesDto> apply(final VirtualDatacenter input)
+                    {
+                        return context.getAsyncApi().getCloudApi()
+                            .listVirtualAppliances(input.unwrap());
+                    }
+                }, userExecutor, maxTime, logger, "getting virtual appliances");
+
+        return DomainWrapper.join(vapps);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualDatacentersImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualDatacentersImpl.java
new file mode 100644
index 0000000..d73e3b4
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualDatacentersImpl.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.jclouds.concurrent.FutureIterables.transformParallel;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.options.VirtualDatacenterOptions;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualDatacenters;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.cloud.VirtualDatacentersDto;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+/**
+ * List virtual datacenters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ListVirtualDatacentersImpl implements ListVirtualDatacenters
+{
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    protected final ExecutorService userExecutor;
+
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Inject(optional = true)
+    @Named(Constants.PROPERTY_REQUEST_TIMEOUT)
+    protected Long maxTime;
+
+    @Inject
+    ListVirtualDatacentersImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(Constants.PROPERTY_USER_THREADS) final ExecutorService userExecutor)
+    {
+        this.context = checkNotNull(context, "context");
+        this.userExecutor = checkNotNull(userExecutor, "userExecutor");
+    }
+
+    @Override
+    public Iterable<VirtualDatacenter> execute()
+    {
+        VirtualDatacenterOptions virtualDatacenterOptions =
+            VirtualDatacenterOptions.builder().build();
+
+        return execute(virtualDatacenterOptions);
+    }
+
+    @Override
+    public Iterable<VirtualDatacenter> execute(final Predicate<VirtualDatacenter> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+    @Override
+    public Iterable<VirtualDatacenter> execute(
+        final VirtualDatacenterOptions virtualDatacenterOptions)
+    {
+        VirtualDatacentersDto result =
+            context.getApi().getCloudApi().listVirtualDatacenters(virtualDatacenterOptions);
+        return wrap(context, VirtualDatacenter.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<VirtualDatacenter> execute(final Predicate<VirtualDatacenter> selector,
+        final VirtualDatacenterOptions virtualDatacenterOptions)
+    {
+        return filter(execute(virtualDatacenterOptions), selector);
+    }
+
+    @Override
+    public Iterable<VirtualDatacenter> execute(final List<Integer> virtualDatacenterIds)
+    {
+        // Find virtual datacenters in concurrent requests
+        return listConcurrentVirtualDatacenters(virtualDatacenterIds);
+    }
+
+    private Iterable<VirtualDatacenter> listConcurrentVirtualDatacenters(final List<Integer> ids)
+    {
+        Iterable<VirtualDatacenterDto> vdcs =
+            transformParallel(ids, new Function<Integer, Future< ? extends VirtualDatacenterDto>>()
+            {
+                @Override
+                public Future<VirtualDatacenterDto> apply(final Integer input)
+                {
+                    return context.getAsyncApi().getCloudApi().getVirtualDatacenter(input);
+                }
+            }, userExecutor, maxTime, logger, "getting virtual datacenters");
+
+        return DomainWrapper.wrap(context, VirtualDatacenter.class, Lists.newArrayList(vdcs));
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualMachinesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualMachinesImpl.java
new file mode 100644
index 0000000..6f0a7c8
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualMachinesImpl.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.jclouds.concurrent.FutureIterables.transformParallel;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineOptions;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualAppliances;
+import org.jclouds.abiquo.strategy.cloud.ListVirtualMachines;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List virtual machines in each virtual datacenter and each virtual appliance.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ListVirtualMachinesImpl implements ListVirtualMachines
+{
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    protected final ExecutorService userExecutor;
+
+    protected final ListVirtualAppliances listVirtualAppliances;
+
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Inject(optional = true)
+    @Named(Constants.PROPERTY_REQUEST_TIMEOUT)
+    protected Long maxTime;
+
+    @Inject
+    ListVirtualMachinesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(Constants.PROPERTY_USER_THREADS) final ExecutorService userExecutor,
+        final ListVirtualAppliances listVirtualAppliances)
+    {
+        super();
+        this.context = checkNotNull(context, "context");
+        this.listVirtualAppliances = checkNotNull(listVirtualAppliances, "listVirtualAppliances");
+        this.userExecutor = checkNotNull(userExecutor, "userExecutor");
+    }
+
+    @Override
+    public Iterable<VirtualMachine> execute()
+    {
+        return execute(VirtualMachineOptions.builder().disablePagination().build());
+    }
+
+    @Override
+    public Iterable<VirtualMachine> execute(final VirtualMachineOptions options)
+    {
+        // Find virtual machines in concurrent requests
+        Iterable<VirtualAppliance> vapps = listVirtualAppliances.execute();
+        Iterable<VirtualMachineWithNodeExtendedDto> vms =
+            listConcurrentVirtualMachines(vapps, options);
+
+        return wrap(context, VirtualMachine.class, vms);
+    }
+
+    @Override
+    public Iterable<VirtualMachine> execute(final Predicate<VirtualMachine> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+    private Iterable<VirtualMachineWithNodeExtendedDto> listConcurrentVirtualMachines(
+        final Iterable<VirtualAppliance> vapps, final VirtualMachineOptions options)
+    {
+        Iterable<VirtualMachinesWithNodeExtendedDto> vms =
+            transformParallel(
+                vapps,
+                new Function<VirtualAppliance, Future< ? extends VirtualMachinesWithNodeExtendedDto>>()
+                {
+                    @Override
+                    public Future<VirtualMachinesWithNodeExtendedDto> apply(
+                        final VirtualAppliance input)
+                    {
+                        return context.getAsyncApi().getCloudApi()
+                            .listVirtualMachines(input.unwrap(), options);
+                    }
+                }, userExecutor, maxTime, logger, "getting virtual machines");
+
+        return DomainWrapper.join(vms);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListCategories.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListCategories.java
new file mode 100644
index 0000000..69e6a40
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListCategories.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config;
+
+import org.jclouds.abiquo.domain.config.Category;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.config.internal.ListCategoriesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List privileges.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListCategoriesImpl.class)
+public interface ListCategories extends ListRootEntities<Category>
+{
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListCurrencies.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListCurrencies.java
new file mode 100644
index 0000000..168762e
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListCurrencies.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config;
+
+import org.jclouds.abiquo.domain.config.Currency;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.config.internal.ListCurrenciesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List currencies
+ * 
+ * @author Susana Acedo
+ */
+@ImplementedBy(ListCurrenciesImpl.class)
+public interface ListCurrencies extends ListRootEntities<Currency>
+{
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListLicenses.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListLicenses.java
new file mode 100644
index 0000000..8eccf96
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListLicenses.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config;
+
+import org.jclouds.abiquo.domain.config.License;
+import org.jclouds.abiquo.domain.config.options.LicenseOptions;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.config.internal.ListLicensesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List licenses.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListLicensesImpl.class)
+public interface ListLicenses extends ListRootEntities<License>
+{
+    public Iterable<License> execute(LicenseOptions options);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListPrivileges.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListPrivileges.java
new file mode 100644
index 0000000..287dc08
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListPrivileges.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config;
+
+import org.jclouds.abiquo.domain.config.Privilege;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.config.internal.ListPrivilegesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List privileges.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListPrivilegesImpl.class)
+public interface ListPrivileges extends ListRootEntities<Privilege>
+{
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListProperties.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListProperties.java
new file mode 100644
index 0000000..1f7f543
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/ListProperties.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config;
+
+import org.jclouds.abiquo.domain.config.SystemProperty;
+import org.jclouds.abiquo.domain.config.options.PropertyOptions;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.config.internal.ListPropertiesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List system properties.
+ * 
+ * @author Francesc Montserrat
+ */
+@ImplementedBy(ListPropertiesImpl.class)
+public interface ListProperties extends ListRootEntities<SystemProperty>
+{
+    public Iterable<SystemProperty> execute(PropertyOptions options);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListCategoriesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListCategoriesImpl.java
new file mode 100644
index 0000000..cefe811
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListCategoriesImpl.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.config.Category;
+import org.jclouds.abiquo.strategy.config.ListCategories;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.appslibrary.CategoriesDto;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List categories.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ListCategoriesImpl implements ListCategories
+{
+    // This strategy does not have still an Executor instance because the current methods call
+    // single api methods
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    ListCategoriesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public Iterable<Category> execute()
+    {
+        CategoriesDto result = context.getApi().getConfigApi().listCategories();
+        return wrap(context, Category.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<Category> execute(final Predicate<Category> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListCurrenciesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListCurrenciesImpl.java
new file mode 100644
index 0000000..d5d9ea8
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListCurrenciesImpl.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.config.Currency;
+import org.jclouds.abiquo.strategy.config.ListCurrencies;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.pricing.CurrenciesDto;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List currencies
+ * 
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ */
+@Singleton
+public class ListCurrenciesImpl implements ListCurrencies
+{
+    // This strategy does not have still an Executor instance because the current methods call
+    // single api methods
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    ListCurrenciesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public Iterable<Currency> execute()
+    {
+        CurrenciesDto result = context.getApi().getPricingApi().listCurrencies();
+        return wrap(context, Currency.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<Currency> execute(final Predicate<Currency> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListLicensesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListLicensesImpl.java
new file mode 100644
index 0000000..15e0c91
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListLicensesImpl.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.config.License;
+import org.jclouds.abiquo.domain.config.options.LicenseOptions;
+import org.jclouds.abiquo.strategy.config.ListLicenses;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.config.LicensesDto;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List licenses.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ListLicensesImpl implements ListLicenses
+{
+    // This strategy does not have still an Executor instance because the current methods call
+    // single api methods
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    ListLicensesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public Iterable<License> execute()
+    {
+        LicensesDto result = context.getApi().getConfigApi().listLicenses();
+        return wrap(context, License.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<License> execute(final LicenseOptions options)
+    {
+        LicensesDto result = context.getApi().getConfigApi().listLicenses(options);
+        return wrap(context, License.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<License> execute(final Predicate<License> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListPrivilegesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListPrivilegesImpl.java
new file mode 100644
index 0000000..a91c933
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListPrivilegesImpl.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.config.Privilege;
+import org.jclouds.abiquo.strategy.config.ListPrivileges;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.PrivilegesDto;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List licenses.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ListPrivilegesImpl implements ListPrivileges
+{
+    // This strategy does not have still an Executor instance because the current methods call
+    // single api methods
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    ListPrivilegesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public Iterable<Privilege> execute()
+    {
+        PrivilegesDto result = context.getApi().getConfigApi().listPrivileges();
+        return wrap(context, Privilege.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<Privilege> execute(final Predicate<Privilege> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListPropertiesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListPropertiesImpl.java
new file mode 100644
index 0000000..8eeae43
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/config/internal/ListPropertiesImpl.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.config.SystemProperty;
+import org.jclouds.abiquo.domain.config.options.PropertyOptions;
+import org.jclouds.abiquo.strategy.config.ListProperties;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.config.SystemPropertiesDto;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List properties.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ListPropertiesImpl implements ListProperties
+{
+    // This strategy does not have still an Executor instance because the current methods call
+    // single api methods
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    ListPropertiesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public Iterable<SystemProperty> execute()
+    {
+        SystemPropertiesDto result = context.getApi().getConfigApi().listSystemProperties();
+        return wrap(context, SystemProperty.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<SystemProperty> execute(final Predicate<SystemProperty> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+    @Override
+    public Iterable<SystemProperty> execute(final PropertyOptions options)
+    {
+        SystemPropertiesDto result =
+            context.getApi().getConfigApi().listSystemProperties(options);
+        return wrap(context, SystemProperty.class, result.getCollection());
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/ListEnterprises.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/ListEnterprises.java
new file mode 100644
index 0000000..48fcb80
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/ListEnterprises.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.enterprise;
+
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.enterprise.internal.ListEnterprisesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List enterprises.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListEnterprisesImpl.class)
+public interface ListEnterprises extends ListRootEntities<Enterprise>
+{
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/ListVirtualMachineTemplates.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/ListVirtualMachineTemplates.java
new file mode 100644
index 0000000..e92034f
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/ListVirtualMachineTemplates.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.enterprise;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.strategy.ListEntities;
+import org.jclouds.abiquo.strategy.enterprise.internal.ListVirtualMachineTemplatesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List all virtual machine templates available to an enterprise.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListVirtualMachineTemplatesImpl.class)
+public interface ListVirtualMachineTemplates extends
+    ListEntities<VirtualMachineTemplate, Enterprise>
+{
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/internal/ListEnterprisesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/internal/ListEnterprisesImpl.java
new file mode 100644
index 0000000..76d9cc2
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/internal/ListEnterprisesImpl.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.enterprise.internal;
+
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Singleton;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.strategy.enterprise.ListEnterprises;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.EnterprisesDto;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List enterprises.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ListEnterprisesImpl implements ListEnterprises
+{
+    // This strategy does not have still an Executor instance because the current methods call
+    // single api methods
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    ListEnterprisesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public Iterable<Enterprise> execute()
+    {
+        EnterprisesDto result = context.getApi().getEnterpriseApi().listEnterprises();
+        return wrap(context, Enterprise.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<Enterprise> execute(final Predicate<Enterprise> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/internal/ListVirtualMachineTemplatesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/internal/ListVirtualMachineTemplatesImpl.java
new file mode 100644
index 0000000..b9d95f0
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/enterprise/internal/ListVirtualMachineTemplatesImpl.java
@@ -0,0 +1,114 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.enterprise.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.jclouds.concurrent.FutureIterables.transformParallel;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.strategy.enterprise.ListVirtualMachineTemplates;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List all virtual machine templates available to an enterprise.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ListVirtualMachineTemplatesImpl implements ListVirtualMachineTemplates
+{
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    protected final ExecutorService userExecutor;
+
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Inject(optional = true)
+    @Named(Constants.PROPERTY_REQUEST_TIMEOUT)
+    protected Long maxTime;
+
+    @Inject
+    ListVirtualMachineTemplatesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(Constants.PROPERTY_USER_THREADS) final ExecutorService userExecutor)
+    {
+        super();
+        this.context = checkNotNull(context, "context");
+        this.userExecutor = checkNotNull(userExecutor, "userExecutor");
+    }
+
+    @Override
+    public Iterable<VirtualMachineTemplate> execute(final Enterprise parent)
+    {
+        // Find virtual machine templates in concurrent requests
+        Iterable<Datacenter> dcs = parent.listAllowedDatacenters();
+        Iterable<VirtualMachineTemplateDto> templates = listConcurrentTemplates(parent, dcs);
+
+        return wrap(context, VirtualMachineTemplate.class, templates);
+    }
+
+    @Override
+    public Iterable<VirtualMachineTemplate> execute(final Enterprise parent,
+        final Predicate<VirtualMachineTemplate> selector)
+    {
+        return filter(execute(parent), selector);
+    }
+
+    private Iterable<VirtualMachineTemplateDto> listConcurrentTemplates(final Enterprise parent,
+        final Iterable<Datacenter> dcs)
+    {
+        Iterable<VirtualMachineTemplatesDto> templates =
+            transformParallel(dcs,
+                new Function<Datacenter, Future< ? extends VirtualMachineTemplatesDto>>()
+                {
+                    @Override
+                    public Future<VirtualMachineTemplatesDto> apply(final Datacenter input)
+                    {
+                        return context.getAsyncApi().getVirtualMachineTemplateApi()
+                            .listVirtualMachineTemplates(parent.getId(), input.getId());
+                    }
+                }, userExecutor, maxTime, logger, "getting virtual machine templates");
+
+        return DomainWrapper.join(templates);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/event/ListEvents.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/event/ListEvents.java
new file mode 100644
index 0000000..a8680d8
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/event/ListEvents.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.event;
+
+import org.jclouds.abiquo.domain.event.Event;
+import org.jclouds.abiquo.domain.event.options.EventOptions;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.event.internal.ListEventsImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List events.
+ * 
+ * @author Vivien Mahé
+ */
+@ImplementedBy(ListEventsImpl.class)
+public interface ListEvents extends ListRootEntities<Event>
+{
+    Iterable<Event> execute(EventOptions options);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/event/internal/ListEventsImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/event/internal/ListEventsImpl.java
new file mode 100644
index 0000000..42ca29c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/event/internal/ListEventsImpl.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.event.internal;
+
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.event.Event;
+import org.jclouds.abiquo.domain.event.options.EventOptions;
+import org.jclouds.abiquo.strategy.event.ListEvents;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.event.EventsDto;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+public class ListEventsImpl implements ListEvents
+{
+    // This strategy does not have still an Executor instance because the current methods call
+    // single api methods
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    ListEventsImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public Iterable<Event> execute()
+    {
+        EventsDto result = context.getApi().getEventApi().listEvents();
+        return wrap(context, Event.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<Event> execute(final EventOptions options)
+    {
+        EventsDto result = context.getApi().getEventApi().listEvents(options);
+        return wrap(context, Event.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<Event> execute(final Predicate<Event> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/ListDatacenters.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/ListDatacenters.java
new file mode 100644
index 0000000..c92869d
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/ListDatacenters.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.infrastructure;
+
+import java.util.List;
+
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.infrastructure.internal.ListDatacentersImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List datacenters.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListDatacentersImpl.class)
+public interface ListDatacenters extends ListRootEntities<Datacenter>
+{
+    Iterable<Datacenter> execute(List<Integer> datacenterIds);
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/ListMachines.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/ListMachines.java
new file mode 100644
index 0000000..4fec2b9
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/ListMachines.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.infrastructure;
+
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+import org.jclouds.abiquo.strategy.ListRootEntities;
+import org.jclouds.abiquo.strategy.infrastructure.internal.ListMachinesImpl;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * List machines in each datacenter and rack.
+ * 
+ * @author Ignasi Barrera
+ */
+@ImplementedBy(ListMachinesImpl.class)
+public interface ListMachines extends ListRootEntities<Machine>
+{
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListDatacentersImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListDatacentersImpl.java
new file mode 100644
index 0000000..0ba7056
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListDatacentersImpl.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.infrastructure.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.jclouds.concurrent.FutureIterables.transformParallel;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.strategy.infrastructure.ListDatacenters;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+/**
+ * List datacenters.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Singleton
+public class ListDatacentersImpl implements ListDatacenters
+{
+
+    protected final RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    protected final ExecutorService userExecutor;
+
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Inject(optional = true)
+    @Named(Constants.PROPERTY_REQUEST_TIMEOUT)
+    protected Long maxTime;
+
+    @Inject
+    ListDatacentersImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(Constants.PROPERTY_USER_THREADS) final ExecutorService userExecutor)
+    {
+        this.context = context;
+        this.userExecutor = checkNotNull(userExecutor, "userExecutor");
+    }
+
+    @Override
+    public Iterable<Datacenter> execute()
+    {
+        DatacentersDto result = context.getApi().getInfrastructureApi().listDatacenters();
+        return wrap(context, Datacenter.class, result.getCollection());
+    }
+
+    @Override
+    public Iterable<Datacenter> execute(final Predicate<Datacenter> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+    @Override
+    public Iterable<Datacenter> execute(final List<Integer> datacenterIds)
+    {
+        // Find virtual datacenters in concurrent requests
+        return listConcurrentDatacenters(datacenterIds);
+    }
+
+    private Iterable<Datacenter> listConcurrentDatacenters(final List<Integer> ids)
+    {
+        Iterable<DatacenterDto> dcs =
+            transformParallel(ids, new Function<Integer, Future< ? extends DatacenterDto>>()
+            {
+                @Override
+                public Future<DatacenterDto> apply(final Integer input)
+                {
+                    return context.getAsyncApi().getInfrastructureApi().getDatacenter(input);
+                }
+            }, userExecutor, maxTime, logger, "getting datacenters");
+
+        return DomainWrapper.wrap(context, Datacenter.class, Lists.newArrayList(dcs));
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListMachinesImpl.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListMachinesImpl.java
new file mode 100644
index 0000000..362d25c
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListMachinesImpl.java
@@ -0,0 +1,133 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.infrastructure.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.filter;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.jclouds.concurrent.FutureIterables.transformParallel;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+import org.jclouds.abiquo.strategy.infrastructure.ListDatacenters;
+import org.jclouds.abiquo.strategy.infrastructure.ListMachines;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.abiquo.server.core.infrastructure.RacksDto;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+
+/**
+ * List machines in each datacenter and rack.
+ * 
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class ListMachinesImpl implements ListMachines
+{
+    protected RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    protected ListDatacenters listDatacenters;
+
+    protected final ExecutorService userExecutor;
+
+    @Resource
+    protected Logger logger = Logger.NULL;
+
+    @Inject(optional = true)
+    @Named(Constants.PROPERTY_REQUEST_TIMEOUT)
+    protected Long maxTime;
+
+    @Inject
+    ListMachinesImpl(final RestContext<AbiquoApi, AbiquoAsyncApi> context,
+        @Named(Constants.PROPERTY_USER_THREADS) final ExecutorService userExecutor,
+        final ListDatacenters listDatacenters)
+    {
+        super();
+        this.context = checkNotNull(context, "context");
+        this.listDatacenters = checkNotNull(listDatacenters, "listDatacenters");
+        this.userExecutor = checkNotNull(userExecutor, "userExecutor");
+    }
+
+    @Override
+    public Iterable<Machine> execute()
+    {
+        // Find machines in concurrent requests
+        Iterable<Datacenter> datacenters = listDatacenters.execute();
+        Iterable<RackDto> racks = listConcurrentRacks(datacenters);
+        Iterable<MachineDto> machines = listConcurrentMachines(racks);
+
+        return wrap(context, Machine.class, machines);
+    }
+
+    @Override
+    public Iterable<Machine> execute(final Predicate<Machine> selector)
+    {
+        return filter(execute(), selector);
+    }
+
+    private Iterable<RackDto> listConcurrentRacks(final Iterable<Datacenter> datacenters)
+    {
+        Iterable<RacksDto> racks =
+            transformParallel(datacenters, new Function<Datacenter, Future< ? extends RacksDto>>()
+            {
+                @Override
+                public Future<RacksDto> apply(final Datacenter input)
+                {
+                    return context.getAsyncApi().getInfrastructureApi()
+                        .listRacks(input.unwrap());
+                }
+            }, userExecutor, maxTime, logger, "getting racks");
+
+        return DomainWrapper.join(racks);
+    }
+
+    private Iterable<MachineDto> listConcurrentMachines(final Iterable<RackDto> racks)
+    {
+        Iterable<MachinesDto> machines =
+            transformParallel(racks, new Function<RackDto, Future< ? extends MachinesDto>>()
+            {
+                @Override
+                public Future<MachinesDto> apply(final RackDto input)
+                {
+                    return context.getAsyncApi().getInfrastructureApi().listMachines(input);
+                }
+            }, userExecutor, maxTime, logger, "getting machines");
+
+        return DomainWrapper.join(machines);
+    }
+
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/suppliers/GetCurrentEnterprise.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/suppliers/GetCurrentEnterprise.java
new file mode 100644
index 0000000..727d438
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/suppliers/GetCurrentEnterprise.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.suppliers;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+
+import com.google.common.base.Supplier;
+
+/**
+ * Gets the current enterprise.
+ * 
+ * @author Ignasi Barrera
+ */
+public class GetCurrentEnterprise implements Supplier<Enterprise>
+{
+    private final GetCurrentUser currentUserSupplier;
+
+    @Inject
+    public GetCurrentEnterprise(final GetCurrentUser currentUserSupplier)
+    {
+        this.currentUserSupplier = checkNotNull(currentUserSupplier, "currentUserSupplier");
+    }
+
+    @Override
+    public Enterprise get()
+    {
+        return currentUserSupplier.get().getEnterprise();
+    }
+}
diff --git a/labs/abiquo/src/main/java/org/jclouds/abiquo/suppliers/GetCurrentUser.java b/labs/abiquo/src/main/java/org/jclouds/abiquo/suppliers/GetCurrentUser.java
new file mode 100644
index 0000000..185a660
--- /dev/null
+++ b/labs/abiquo/src/main/java/org/jclouds/abiquo/suppliers/GetCurrentUser.java
@@ -0,0 +1,57 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.suppliers;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+
+import javax.inject.Inject;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.rest.RestContext;
+
+import com.abiquo.server.core.enterprise.UserDto;
+import com.google.common.base.Supplier;
+
+/**
+ * Gets the current user.
+ * 
+ * @author Ignasi Barrera
+ */
+public class GetCurrentUser implements Supplier<User>
+{
+    private RestContext<AbiquoApi, AbiquoAsyncApi> context;
+
+    @Inject
+    public GetCurrentUser(final RestContext<AbiquoApi, AbiquoAsyncApi> context)
+    {
+        this.context = checkNotNull(context, "context");
+    }
+
+    @Override
+    public User get()
+    {
+        UserDto user = context.getApi().getAdminApi().getCurrentUser();
+        return wrap(context, User.class, user);
+    }
+
+}
diff --git a/labs/abiquo/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/labs/abiquo/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
new file mode 100644
index 0000000..642f443
--- /dev/null
+++ b/labs/abiquo/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata
@@ -0,0 +1 @@
+org.jclouds.abiquo.AbiquoApiMetadata
\ No newline at end of file
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/AbiquoApiMetadataTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/AbiquoApiMetadataTest.java
new file mode 100644
index 0000000..2e6486d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/AbiquoApiMetadataTest.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.apis.Apis;
+import org.jclouds.compute.internal.BaseComputeServiceApiMetadataTest;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link AbiquoApiMetadata} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AbiquoApiMetadataTest")
+public class AbiquoApiMetadataTest extends BaseComputeServiceApiMetadataTest
+{
+
+    public AbiquoApiMetadataTest()
+    {
+        super(new AbiquoApiMetadata());
+    }
+
+    public void testAbiquoApiRegistered()
+    {
+        ApiMetadata api = Apis.withId("abiquo");
+
+        assertNotNull(api);
+        assertTrue(api instanceof AbiquoApiMetadata);
+        assertEquals(api.getId(), "abiquo");
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/AbiquoDelegateApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/AbiquoDelegateApiTest.java
new file mode 100644
index 0000000..8f99cba
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/AbiquoDelegateApiTest.java
@@ -0,0 +1,95 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+import org.jclouds.abiquo.features.BaseAbiquoAsyncApiTest;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests asynchronous and synchronous API delegates.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AbiquoDelegateApiTest")
+public class AbiquoDelegateApiTest extends BaseAbiquoAsyncApiTest<AbiquoAsyncApi>
+{
+    private AbiquoAsyncApi asyncApi;
+
+    private AbiquoApi syncApi;
+
+    @BeforeClass
+    @Override
+    protected void setupFactory() throws IOException
+    {
+        super.setupFactory();
+        asyncApi = injector.getInstance(AbiquoAsyncApi.class);
+        syncApi = injector.getInstance(AbiquoApi.class);
+    }
+
+    public void testSync() throws SecurityException, NoSuchMethodException, InterruptedException,
+        ExecutionException
+    {
+        assertNotNull(syncApi.getAdminApi());
+        assertNotNull(syncApi.getConfigApi());
+        assertNotNull(syncApi.getInfrastructureApi());
+        assertNotNull(syncApi.getEnterpriseApi());
+        assertNotNull(syncApi.getCloudApi());
+        assertNotNull(syncApi.getVirtualMachineTemplateApi());
+        assertNotNull(syncApi.getTaskApi());
+        assertNotNull(syncApi.getPricingApi());
+    }
+
+    public void testAsync() throws SecurityException, NoSuchMethodException, InterruptedException,
+        ExecutionException
+    {
+        assertNotNull(asyncApi.getAdminApi());
+        assertNotNull(asyncApi.getConfigApi());
+        assertNotNull(asyncApi.getInfrastructureApi());
+        assertNotNull(asyncApi.getEnterpriseApi());
+        assertNotNull(asyncApi.getCloudApi());
+        assertNotNull(asyncApi.getVirtualMachineTemplateApi());
+        assertNotNull(asyncApi.getTaskApi());
+        assertNotNull(asyncApi.getPricingApi());
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<AbiquoAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<AbiquoAsyncApi>>()
+        {
+        };
+    }
+
+    @Override
+    protected void checkFilters(final HttpRequest request)
+    {
+
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/AppendToPathTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/AppendToPathTest.java
new file mode 100644
index 0000000..960076a
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/AppendToPathTest.java
@@ -0,0 +1,63 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.http.HttpRequest;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link AppendToPath} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AppendToPathTest")
+public class AppendToPathTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        AppendToPath binder = new AppendToPath();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    public void testBindString()
+    {
+        AppendToPath binder = new AppendToPath();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        HttpRequest newRequest = binder.bindToRequest(request, "expanded/path");
+        assertEquals(newRequest.getRequestLine(), "GET http://localhost/expanded/path HTTP/1.1");
+    }
+
+    public void testBindNumber()
+    {
+        AppendToPath binder = new AppendToPath();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        HttpRequest newRequest = binder.bindToRequest(request, 57);
+        assertEquals(newRequest.getRequestLine(), "GET http://localhost/57 HTTP/1.1");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindLinkToPathAndAcceptHeaderTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindLinkToPathAndAcceptHeaderTest.java
new file mode 100644
index 0000000..5ef0eff
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindLinkToPathAndAcceptHeaderTest.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URI;
+
+import javax.ws.rs.core.HttpHeaders;
+
+import org.jclouds.http.HttpRequest;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BindLinkToPathAndAcceptHeader} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindLinkToPathAndAcceptHeaderTest")
+public class BindLinkToPathAndAcceptHeaderTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindLinkToPathAndAcceptHeader binder = new BindLinkToPathAndAcceptHeader();
+        binder.addHeader(null, HttpHeaders.ACCEPT, null);
+    }
+
+    public void testAddHeader()
+    {
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+
+        BindLinkToPathAndAcceptHeader binder = new BindLinkToPathAndAcceptHeader();
+        HttpRequest updatedRequest =
+            binder.addHeader(request, HttpHeaders.ACCEPT, "application/vnd.abiquo.datacenters+xml");
+
+        String accept = updatedRequest.getFirstHeaderOrNull(HttpHeaders.ACCEPT);
+
+        assertNotNull(accept);
+        assertEquals(accept, "application/vnd.abiquo.datacenters+xml");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindLinkToPathTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindLinkToPathTest.java
new file mode 100644
index 0000000..55e6840
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindLinkToPathTest.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+
+/**
+ * Unit tests for the {@link BindLinkToPath} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindLinkToPathTest")
+public class BindLinkToPathTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testGetNewEnpointNullInput()
+    {
+        BindLinkToPath binder = new BindLinkToPath();
+        binder.getNewEndpoint(null, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testGetNewEnpointInvalidInput()
+    {
+        BindLinkToPath binder = new BindLinkToPath();
+        binder.getNewEndpoint(null, new Object());
+    }
+
+    public void testGetNewEnpoint()
+    {
+        BindLinkToPath binder = new BindLinkToPath();
+        assertEquals(binder.getNewEndpoint(null, new RESTLink("edit", "http://foo/bar")),
+            "http://foo/bar");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindToPathTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindToPathTest.java
new file mode 100644
index 0000000..066d38e
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/BindToPathTest.java
@@ -0,0 +1,204 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders;
+
+import static org.testng.Assert.assertEquals;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.abiquo.rest.annotations.EndpointLink;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.binders.BindException;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Unit tests for the {@link BindToPath} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindToPathTest")
+public class BindToPathTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullRequest() throws SecurityException, NoSuchMethodException
+    {
+        BindToPath binder = new BindToPath();
+        binder.bindToRequest(null, new Object());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidRequestType() throws SecurityException, NoSuchMethodException
+    {
+        BindToPath binder = new BindToPath();
+        binder.bindToRequest(
+            HttpRequest.builder().method("m").endpoint("http://localhost").build(), new Object());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput() throws SecurityException, NoSuchMethodException
+    {
+        Method withEndpointLink =
+            TestEndpointLink.class.getMethod("withEndpointLink", TestDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestEndpointLink.class)
+                .javaMethod(withEndpointLink).args(ImmutableList.<Object> of(new TestDto()))
+                .method(HttpMethod.GET).endpoint(URI.create("http://localhost")).build();
+
+        BindToPath binder = new BindToPath();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidInputType() throws SecurityException, NoSuchMethodException
+    {
+        Method withEndpointLink =
+            TestEndpointLink.class.getMethod("withEndpointLink", TestDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestEndpointLink.class)
+                .javaMethod(withEndpointLink).args(ImmutableList.<Object> of(new TestDto()))
+                .method(HttpMethod.GET).endpoint(URI.create("http://localhost")).build();
+
+        BindToPath binder = new BindToPath();
+        binder.bindToRequest(request, new Object());
+    }
+
+    @Test(expectedExceptions = BindException.class)
+    public void testAnnotationNotPresent() throws SecurityException, NoSuchMethodException
+    {
+        TestDto dto = new TestDto();
+        Method withoutEndpointLink =
+            TestEndpointLink.class.getMethod("withoutEndpointLink", TestDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestEndpointLink.class)
+                .javaMethod(withoutEndpointLink).args(ImmutableList.<Object> of(dto))
+                .method(HttpMethod.GET).endpoint(URI.create("http://localhost")).build();
+
+        BindToPath binder = new BindToPath();
+        binder.bindToRequest(request, dto);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testLinkNotPresent() throws SecurityException, NoSuchMethodException
+    {
+        TestDto dto = new TestDto();
+        Method withUnexistingLink =
+            TestEndpointLink.class.getMethod("withUnexistingLink", TestDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestEndpointLink.class)
+                .javaMethod(withUnexistingLink).args(ImmutableList.<Object> of(dto))
+                .method(HttpMethod.GET).endpoint(URI.create("http://localhost")).build();
+
+        BindToPath binder = new BindToPath();
+        binder.bindToRequest(request, dto);
+    }
+
+    public void testBindWithoutParameters() throws SecurityException, NoSuchMethodException
+    {
+        TestDto dto = new TestDto();
+        Method withEndpointLink =
+            TestEndpointLink.class.getMethod("withEndpointLink", TestDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestEndpointLink.class)
+                .javaMethod(withEndpointLink).args(ImmutableList.<Object> of(dto))
+                .method(HttpMethod.GET).endpoint(URI.create("http://localhost")).build();
+
+        BindToPath binder = new BindToPath();
+        GeneratedHttpRequest newRequest = binder.bindToRequest(request, dto);
+        assertEquals(newRequest.getRequestLine(), "GET http://linkuri HTTP/1.1");
+    }
+
+    public void testBindWithQueryParameters() throws SecurityException, NoSuchMethodException
+    {
+        TestDto dto = new TestDto();
+        Method withEndpointLink =
+            TestEndpointLink.class.getMethod("withEndpointLink", TestDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestEndpointLink.class)
+                .javaMethod(withEndpointLink).args(ImmutableList.<Object> of(dto))
+                .method(HttpMethod.GET).endpoint(URI.create("http://localhost?param=value"))
+                .build();
+
+        BindToPath binder = new BindToPath();
+        GeneratedHttpRequest newRequest = binder.bindToRequest(request, dto);
+        assertEquals(newRequest.getRequestLine(), "GET http://linkuri?param=value HTTP/1.1");
+    }
+
+    public void testBindWithQueryAndMatrixParameters() throws SecurityException,
+        NoSuchMethodException
+    {
+        TestDto dto = new TestDto();
+        Method withEndpointLink =
+            TestEndpointLink.class.getMethod("withEndpointLink", TestDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestEndpointLink.class)
+                .javaMethod(withEndpointLink).args(ImmutableList.<Object> of(dto))
+                .method(HttpMethod.GET)
+                .endpoint(URI.create("http://localhost?param=value;matrix=value2")).build();
+
+        BindToPath binder = new BindToPath();
+        GeneratedHttpRequest newRequest = binder.bindToRequest(request, dto);
+        assertEquals(newRequest.getRequestLine(),
+            "GET http://linkuri?param=value;matrix=value2 HTTP/1.1");
+    }
+
+    static interface TestEndpointLink
+    {
+        @GET
+        void withEndpointLink(@EndpointLink("edit") TestDto dto);
+
+        @GET
+        void withUnexistingLink(@EndpointLink("unexisting") TestDto dto);
+
+        @GET
+        void withoutEndpointLink(TestDto dto);
+    }
+
+    static class TestDto extends SingleResourceTransportDto
+    {
+        private static final long serialVersionUID = 1L;
+
+        public TestDto()
+        {
+            addLink(new RESTLink("edit", "http://linkuri"));
+        }
+
+        @Override
+        public String getMediaType()
+        {
+            return MediaType.APPLICATION_XML;
+        }
+
+        @Override
+        public String getBaseMediaType()
+        {
+            return MediaType.APPLICATION_XML;
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindHardDiskRefsToPayloadTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindHardDiskRefsToPayloadTest.java
new file mode 100644
index 0000000..9ed0433
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindHardDiskRefsToPayloadTest.java
@@ -0,0 +1,95 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+import static org.jclouds.abiquo.util.Assert.assertPayloadEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jclouds.abiquo.domain.CloudResources;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+
+/**
+ * Unit tests for the {@link BindHardDiskRefsToPayload} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindHardDiskRefsToPayloadTest")
+public class BindHardDiskRefsToPayloadTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindHardDiskRefsToPayload binder = new BindHardDiskRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindHardDiskRefsToPayload binder = new BindHardDiskRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    public void testBindEmptyArray() throws IOException
+    {
+        BindHardDiskRefsToPayload binder = new BindHardDiskRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new DiskManagementDto[] {});
+        assertPayloadEquals(request.getPayload(), withHeader("<links/>"), LinksDto.class);
+    }
+
+    public void testBindSingleHardDisk() throws IOException
+    {
+        DiskManagementDto hardDisk = CloudResources.hardDiskPut();
+        BindHardDiskRefsToPayload binder = new BindHardDiskRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new DiskManagementDto[] {hardDisk});
+        assertPayloadEquals(request.getPayload(), withHeader("<links><link href=\""
+            + hardDisk.getEditLink().getHref() + "\" rel=\"" + binder.getRelToUse(hardDisk)
+            + "\"/></links>"), LinksDto.class);
+    }
+
+    public void testBindMultipleHardDisks() throws IOException
+    {
+        DiskManagementDto hardDisk = CloudResources.hardDiskPut();
+        BindHardDiskRefsToPayload binder = new BindHardDiskRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new DiskManagementDto[] {hardDisk, hardDisk});
+        assertPayloadEquals(request.getPayload(), withHeader("<links><link href=\""
+            + hardDisk.getEditLink().getHref() + "\" rel=\"" + binder.getRelToUse(hardDisk)
+            + "\"/></links>"), LinksDto.class);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindIpRefToPayloadTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindIpRefToPayloadTest.java
new file mode 100644
index 0000000..30b22df
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindIpRefToPayloadTest.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+import static org.jclouds.abiquo.util.Assert.assertPayloadEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jclouds.abiquo.domain.NetworkResources;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+
+/**
+ * Unit tests for the {@link BindIpRefToPayload} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindIpRefToPayloadTest")
+public class BindIpRefToPayloadTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindIpRefToPayload binder = new BindIpRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindIpRefToPayload binder = new BindIpRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    public void testBindIpRef() throws IOException
+    {
+        PrivateIpDto ip = NetworkResources.privateIpPut();
+        RESTLink selfLink = ip.searchLink("self");
+        BindIpRefToPayload binder = new BindIpRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, ip);
+        assertPayloadEquals(
+            request.getPayload(),
+            withHeader("<links><link href=\"" + selfLink.getHref() + "\" rel=\""
+                + selfLink.getTitle() + "\"/></links>"), LinksDto.class);
+
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindIpRefsToPayloadTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindIpRefsToPayloadTest.java
new file mode 100644
index 0000000..55d3016
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindIpRefsToPayloadTest.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+import static org.jclouds.abiquo.util.Assert.assertPayloadEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jclouds.abiquo.domain.NetworkResources;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.AbstractIpDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+
+/**
+ * Unit tests for the {@link BindIpRefsToPayload} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindIpRefsToPayloadTest")
+public class BindIpRefsToPayloadTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindIpRefsToPayload binder = new BindIpRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindIpRefsToPayload binder = new BindIpRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    public void testBindEmptyArray() throws IOException
+    {
+        BindIpRefsToPayload binder = new BindIpRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new AbstractIpDto[] {});
+        assertPayloadEquals(request.getPayload(), withHeader("<links/>"), LinksDto.class);
+    }
+
+    public void testBindSingleIp() throws IOException
+    {
+        PrivateIpDto ip = NetworkResources.privateIpPut();
+        BindIpRefsToPayload binder = new BindIpRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new AbstractIpDto[] {ip});
+        assertPayloadEquals(request.getPayload(), withHeader("<links><link href=\""
+            + ip.searchLink("self").getHref() + "\" rel=\"" + ip.searchLink("self").getTitle()
+            + "\"/></links>"), LinksDto.class);
+    }
+
+    public void testBindMultipleIps() throws IOException
+    {
+        PrivateIpDto ip = NetworkResources.privateIpPut();
+        BindIpRefsToPayload binder = new BindIpRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new AbstractIpDto[] {ip, ip});
+        assertPayloadEquals(request.getPayload(), withHeader("<links><link href=\""
+            + ip.searchLink("self").getHref() + "\" rel=\"" + ip.searchLink("self").getTitle()
+            + "\"/></links>"), LinksDto.class);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindMoveVolumeToPathTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindMoveVolumeToPathTest.java
new file mode 100644
index 0000000..aba9fec
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindMoveVolumeToPathTest.java
@@ -0,0 +1,84 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.testng.Assert.assertEquals;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+
+import javax.ws.rs.HttpMethod;
+
+import org.jclouds.abiquo.domain.CloudResources;
+import org.jclouds.abiquo.features.CloudAsyncApi;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Unit tests for the {@link BindMoveVolumeToPath} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindMoveVolumeToPathTest")
+public class BindMoveVolumeToPathTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput() throws SecurityException, NoSuchMethodException
+    {
+        BindMoveVolumeToPath binder = new BindMoveVolumeToPath();
+        binder.getNewEndpoint(generatedHttpRequest(), null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidInputType() throws SecurityException, NoSuchMethodException
+    {
+        BindMoveVolumeToPath binder = new BindMoveVolumeToPath();
+        binder.getNewEndpoint(generatedHttpRequest(), new Object());
+    }
+
+    public void testGetNewEndpoint() throws SecurityException, NoSuchMethodException
+    {
+        BindMoveVolumeToPath binder = new BindMoveVolumeToPath();
+        String newEndpoint =
+            binder.getNewEndpoint(generatedHttpRequest(), CloudResources.volumePut());
+        assertEquals(newEndpoint,
+            "http://localhost/api/cloud/virtualdatacenters/1/volumes/1/action/move");
+    }
+
+    private static GeneratedHttpRequest generatedHttpRequest() throws SecurityException,
+        NoSuchMethodException
+    {
+        Method withEndpointLink =
+            CloudAsyncApi.class.getMethod("moveVolume", VolumeManagementDto.class,
+                VirtualDatacenterDto.class);
+        return GeneratedHttpRequest
+            .builder()
+            .declaring(CloudAsyncApi.class)
+            .javaMethod(withEndpointLink)
+            .args(
+                ImmutableList.<Object> of(CloudResources.volumePut(),
+                    CloudResources.virtualDatacenterPut())).method(HttpMethod.POST)
+            .endpoint(URI.create("http://localhost")).build();
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindNetworkConfigurationRefToPayloadTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindNetworkConfigurationRefToPayloadTest.java
new file mode 100644
index 0000000..15718cd
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindNetworkConfigurationRefToPayloadTest.java
@@ -0,0 +1,158 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+import static org.jclouds.abiquo.util.Assert.assertPayloadEquals;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.NoSuchElementException;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.HttpMethod;
+
+import org.jclouds.abiquo.domain.CloudResources;
+import org.jclouds.abiquo.domain.NetworkResources;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.cloud.VirtualMachineDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Unit tests for the {@link BindNetworkConfigurationRefToPayload} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindNetworkConfigurationRefToPayloadTest")
+public class BindNetworkConfigurationRefToPayloadTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullRequest() throws SecurityException, NoSuchMethodException
+    {
+        BindNetworkConfigurationRefToPayload binder =
+            new BindNetworkConfigurationRefToPayload(new JAXBParser("false"));
+        binder.bindToRequest(null, new Object());
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidRequestType() throws SecurityException, NoSuchMethodException
+    {
+        BindNetworkConfigurationRefToPayload binder =
+            new BindNetworkConfigurationRefToPayload(new JAXBParser("false"));
+
+        binder.bindToRequest(
+            HttpRequest.builder().method("m").endpoint("http://localhost").build(), new Object());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput() throws SecurityException, NoSuchMethodException
+    {
+        VirtualMachineDto vm = CloudResources.virtualMachinePut();
+
+        Method method =
+            TestNetworkConfig.class.getMethod("withAll", VirtualMachineDto.class,
+                VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestNetworkConfig.class).javaMethod(method)
+                .args(ImmutableList.<Object> of(vm, null)).method(HttpMethod.GET)
+                .endpoint(URI.create("http://localhost")).build();
+
+        BindNetworkConfigurationRefToPayload binder =
+            new BindNetworkConfigurationRefToPayload(new JAXBParser("false"));
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput() throws SecurityException, NoSuchMethodException
+    {
+        VirtualMachineDto vm = CloudResources.virtualMachinePut();
+        Object network = new Object();
+
+        Method method =
+            TestNetworkConfig.class.getMethod("withAll", VirtualMachineDto.class,
+                VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestNetworkConfig.class).javaMethod(method)
+                .args(ImmutableList.<Object> of(vm, network)).method(HttpMethod.GET)
+                .endpoint(URI.create("http://localhost")).build();
+
+        BindNetworkConfigurationRefToPayload binder =
+            new BindNetworkConfigurationRefToPayload(new JAXBParser("false"));
+        binder.bindToRequest(request, network);
+    }
+
+    @Test(expectedExceptions = NoSuchElementException.class)
+    public void testBindNetworkConfigurationRefWithoutVirtualMachine() throws SecurityException,
+        NoSuchMethodException
+    {
+        VLANNetworkDto network = NetworkResources.privateNetworkPut();
+
+        Method method =
+            TestNetworkConfig.class.getMethod("withoutVirtualMachine", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestNetworkConfig.class).javaMethod(method)
+                .args(ImmutableList.<Object> of(network)).method(HttpMethod.GET)
+                .endpoint(URI.create("http://localhost")).build();
+
+        BindNetworkConfigurationRefToPayload binder =
+            new BindNetworkConfigurationRefToPayload(new JAXBParser("false"));
+        binder.bindToRequest(request, network);
+    }
+
+    public void testBindNetworkConfigurationRef() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        VirtualMachineDto vm = CloudResources.virtualMachinePut();
+        VLANNetworkDto network = NetworkResources.privateNetworkPut();
+
+        Method method =
+            TestNetworkConfig.class.getMethod("withAll", VirtualMachineDto.class,
+                VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(TestNetworkConfig.class).javaMethod(method)
+                .args(ImmutableList.<Object> of(vm, network)).method(HttpMethod.GET)
+                .endpoint(URI.create("http://localhost")).build();
+
+        BindNetworkConfigurationRefToPayload binder =
+            new BindNetworkConfigurationRefToPayload(new JAXBParser("false"));
+
+        String configLink = vm.searchLink("configurations").getHref() + "/" + network.getId();
+
+        GeneratedHttpRequest newRequest = binder.bindToRequest(request, network);
+        assertPayloadEquals(newRequest.getPayload(), withHeader("<links><link href=\"" + configLink
+            + "\" rel=\"network_configuration\"/></links>"), LinksDto.class);
+    }
+
+    static interface TestNetworkConfig
+    {
+        @GET
+        void withoutVirtualMachine(VLANNetworkDto network);
+
+        @GET
+        void withAll(VirtualMachineDto virtualMachine, VLANNetworkDto network);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindNetworkRefToPayloadTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindNetworkRefToPayloadTest.java
new file mode 100644
index 0000000..d4d896f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindNetworkRefToPayloadTest.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+import static org.jclouds.abiquo.util.Assert.assertPayloadEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jclouds.abiquo.domain.NetworkResources;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+
+/**
+ * Unit tests for the {@link BindNetworkRefToPayload} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindNetworkRefToPayloadTest")
+public class BindNetworkRefToPayloadTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindNetworkRefToPayload binder = new BindNetworkRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindNetworkRefToPayload binder = new BindNetworkRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    public void testBindNetworkRef() throws IOException
+    {
+        VLANNetworkDto network = NetworkResources.privateNetworkPut();
+        BindNetworkRefToPayload binder = new BindNetworkRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, network);
+        assertPayloadEquals(request.getPayload(), withHeader("<links><link href=\""
+            + network.getEditLink().getHref() + "\" rel=\"internalnetwork\"/></links>"),
+            LinksDto.class);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindUnmanagedIpRefToPayloadTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindUnmanagedIpRefToPayloadTest.java
new file mode 100644
index 0000000..208b33d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindUnmanagedIpRefToPayloadTest.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+import static org.jclouds.abiquo.util.Assert.assertPayloadEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jclouds.abiquo.domain.NetworkResources;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+
+/**
+ * Unit tests for the {@link BindUnmanagedIpRefToPayload} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindUnmanagedIpRefToPayloadTest")
+public class BindUnmanagedIpRefToPayloadTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindUnmanagedIpRefToPayload binder =
+            new BindUnmanagedIpRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindUnmanagedIpRefToPayload binder =
+            new BindUnmanagedIpRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    public void testBindUnmanagedNetworkIpRef() throws IOException
+    {
+        VLANNetworkDto network = NetworkResources.unmanagedNetworkPut();
+        RESTLink ipsLink = network.searchLink("ips");
+        BindUnmanagedIpRefToPayload binder =
+            new BindUnmanagedIpRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, network);
+        assertPayloadEquals(request.getPayload(),
+            withHeader("<links><link href=\"" + ipsLink.getHref()
+                + "\" rel=\"unmanagedip\"/></links>"), LinksDto.class);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindVirtualDatacenterRefToPayloadTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindVirtualDatacenterRefToPayloadTest.java
new file mode 100644
index 0000000..12204d4
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindVirtualDatacenterRefToPayloadTest.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+import static org.jclouds.abiquo.util.Assert.assertPayloadEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jclouds.abiquo.domain.CloudResources;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+
+/**
+ * Unit tests for the {@link BindVirtualDatacenterRefToPayload} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindVirtualDatacenterRefToPayloadTest")
+public class BindVirtualDatacenterRefToPayloadTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindVirtualDatacenterRefToPayload binder =
+            new BindVirtualDatacenterRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindVirtualDatacenterRefToPayload binder =
+            new BindVirtualDatacenterRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    public void testBindSingleVolume() throws IOException
+    {
+        VirtualDatacenterDto vdc = CloudResources.virtualDatacenterPut();
+        BindVirtualDatacenterRefToPayload binder =
+            new BindVirtualDatacenterRefToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, vdc);
+        assertPayloadEquals(request.getPayload(), withHeader("<links><link href=\""
+            + vdc.getEditLink().getHref() + "\" rel=\"virtualdatacenter\"/></links>"),
+            LinksDto.class);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindVolumeRefsToPayloadTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindVolumeRefsToPayloadTest.java
new file mode 100644
index 0000000..8aef3a3
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/cloud/BindVolumeRefsToPayloadTest.java
@@ -0,0 +1,95 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.cloud;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+import static org.jclouds.abiquo.util.Assert.assertPayloadEquals;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jclouds.abiquo.domain.CloudResources;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+
+/**
+ * Unit tests for the {@link BindVolumeRefsToPayload} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindVolumeRefsToPayloadTest")
+public class BindVolumeRefsToPayloadTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindVolumeRefsToPayload binder = new BindVolumeRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindVolumeRefsToPayload binder = new BindVolumeRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    public void testBindEmptyArray() throws IOException
+    {
+        BindVolumeRefsToPayload binder = new BindVolumeRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new VolumeManagementDto[] {});
+        assertPayloadEquals(request.getPayload(), withHeader("<links/>"), LinksDto.class);
+    }
+
+    public void testBindSingleVolume() throws IOException
+    {
+        VolumeManagementDto volume = CloudResources.volumePut();
+        BindVolumeRefsToPayload binder = new BindVolumeRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new VolumeManagementDto[] {volume});
+        assertPayloadEquals(request.getPayload(), withHeader("<links><link href=\""
+            + volume.getEditLink().getHref() + "\" rel=\"" + binder.getRelToUse(volume)
+            + "\"/></links>"), LinksDto.class);
+    }
+
+    public void testBindMultipleVolumes() throws IOException
+    {
+        VolumeManagementDto volume = CloudResources.volumePut();
+        BindVolumeRefsToPayload binder = new BindVolumeRefsToPayload(new JAXBParser("false"));
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        request = binder.bindToRequest(request, new VolumeManagementDto[] {volume, volume});
+        assertPayloadEquals(request.getPayload(), withHeader("<links><link href=\""
+            + volume.getEditLink().getHref() + "\" rel=\"" + binder.getRelToUse(volume)
+            + "\"/></links>"), LinksDto.class);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/AppendMachineIdToPathTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/AppendMachineIdToPathTest.java
new file mode 100644
index 0000000..e8ba7e0
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/AppendMachineIdToPathTest.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.abiquo.functions.infrastructure.ParseMachineId;
+import org.jclouds.http.HttpRequest;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.MachineDto;
+
+/**
+ * Unit tests for the {@link AppendMachineIdToPath} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AppendMachineIdToPathTest")
+public class AppendMachineIdToPathTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testGetValueWithNullInput()
+    {
+        AppendMachineIdToPath binder = new AppendMachineIdToPath(new ParseMachineId());
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.getValue(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testGetValueWithInvalidInput()
+    {
+        AppendMachineIdToPath binder = new AppendMachineIdToPath(new ParseMachineId());
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.getValue(request, new Object());
+    }
+
+    public void testGetValue()
+    {
+        AppendMachineIdToPath binder = new AppendMachineIdToPath(new ParseMachineId());
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+
+        MachineDto machine = new MachineDto();
+        machine.setId(5);
+        assertEquals(binder.getValue(request, machine), "5");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/AppendRemoteServiceTypeToPathTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/AppendRemoteServiceTypeToPathTest.java
new file mode 100644
index 0000000..50f20fa
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/AppendRemoteServiceTypeToPathTest.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.abiquo.functions.infrastructure.ParseRemoteServiceType;
+import org.jclouds.http.HttpRequest;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.RemoteServiceType;
+
+/**
+ * Unit tests for the {@link AppendRemoteServiceTypeToPath} binder.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AppendRemoteServiceTypeToPathTest")
+public class AppendRemoteServiceTypeToPathTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testGetValueWithNullInput()
+    {
+        AppendRemoteServiceTypeToPath binder =
+            new AppendRemoteServiceTypeToPath(new ParseRemoteServiceType());
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.getValue(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testGetValueWithInvalidInput()
+    {
+        AppendRemoteServiceTypeToPath binder =
+            new AppendRemoteServiceTypeToPath(new ParseRemoteServiceType());
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.getValue(request, new Object());
+    }
+
+    public void testGetValue()
+    {
+        AppendRemoteServiceTypeToPath binder =
+            new AppendRemoteServiceTypeToPath(new ParseRemoteServiceType());
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+
+        assertEquals(binder.getValue(request, RemoteServiceType.VIRTUAL_SYSTEM_MONITOR),
+            "virtualsystemmonitor");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/BindSupportedDevicesLinkToPathTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/BindSupportedDevicesLinkToPathTest.java
new file mode 100644
index 0000000..47358b6
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/BindSupportedDevicesLinkToPathTest.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+
+import javax.ws.rs.HttpMethod;
+
+import org.jclouds.abiquo.features.InfrastructureAsyncApi;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Unit tests for the {@link BindSupportedDevicesLinkToPath} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BindSupportedDevicesLinkToPathTest")
+public class BindSupportedDevicesLinkToPathTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testGetNewEnpointNullInput()
+    {
+        BindSupportedDevicesLinkToPath binder = new BindSupportedDevicesLinkToPath();
+        binder.getNewEndpoint(null, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testGetNewEnpointInvalidInput()
+    {
+        BindSupportedDevicesLinkToPath binder = new BindSupportedDevicesLinkToPath();
+        binder.getNewEndpoint(null, new Object());
+    }
+
+    public void testGetNewEnpoint() throws Exception
+    {
+        DatacenterDto datacenter = new DatacenterDto();
+        datacenter.addLink(new RESTLink("devices", "http://foo/bar"));
+
+        BindSupportedDevicesLinkToPath binder = new BindSupportedDevicesLinkToPath();
+
+        Method withEndpointLink =
+            InfrastructureAsyncApi.class.getMethod("listSupportedStorageDevices",
+                DatacenterDto.class);
+
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(InfrastructureAsyncApi.class)
+                .javaMethod(withEndpointLink).args(ImmutableList.<Object> of(datacenter))
+                .method(HttpMethod.GET).endpoint(URI.create("http://foo/bar")).build();
+
+        assertEquals(binder.getNewEndpoint(request, datacenter), "http://foo/bar/action/supported");
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testGetNewEnpointWithoutLink() throws Exception
+    {
+        DatacenterDto datacenter = new DatacenterDto();
+
+        BindSupportedDevicesLinkToPath binder = new BindSupportedDevicesLinkToPath();
+
+        Method withEndpointLink =
+            InfrastructureAsyncApi.class.getMethod("listSupportedStorageDevices",
+                DatacenterDto.class);
+
+        GeneratedHttpRequest request =
+            GeneratedHttpRequest.builder().declaring(InfrastructureAsyncApi.class)
+                .javaMethod(withEndpointLink).args(ImmutableList.<Object> of(datacenter))
+                .method(HttpMethod.GET).endpoint(URI.create("http://foo/bar")).build();
+
+        assertEquals(binder.getNewEndpoint(request, datacenter), "http://foo/bar/action/supported");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindLogicServerParametersTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindLogicServerParametersTest.java
new file mode 100644
index 0000000..16920db
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindLogicServerParametersTest.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure.ucs;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.http.HttpRequest;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+
+/**
+ * Unit tests for the {@link BindLogicServerParameters} binder.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "BindLogicServerParametersTest")
+public class BindLogicServerParametersTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindLogicServerParameters binder = new BindLogicServerParameters();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindLogicServerParameters binder = new BindLogicServerParameters();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testBindLogicServerWithEmptyName()
+    {
+        BindLogicServerParameters binder = new BindLogicServerParameters();
+        LogicServerDto dto = new LogicServerDto();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, dto);
+    }
+
+    public void testBindLogicServer()
+    {
+        BindLogicServerParameters binder = new BindLogicServerParameters();
+        LogicServerDto dto = new LogicServerDto();
+        dto.setName("name");
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        HttpRequest newRequest = binder.bindToRequest(request, dto);
+        assertEquals(newRequest.getRequestLine(), "GET http://localhost?lsName=name HTTP/1.1");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindOrganizationParametersTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindOrganizationParametersTest.java
new file mode 100644
index 0000000..3e47226
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/binders/infrastructure/ucs/BindOrganizationParametersTest.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.binders.infrastructure.ucs;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.http.HttpRequest;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.OrganizationDto;
+
+/**
+ * Unit tests for the {@link BindOrganizationParameters} binder.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "BindOrganizationParametersTest")
+public class BindOrganizationParametersTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        BindOrganizationParameters binder = new BindOrganizationParameters();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidTypeInput()
+    {
+        BindOrganizationParameters binder = new BindOrganizationParameters();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, new Object());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testBindLogicServerWithEmptyName()
+    {
+        BindOrganizationParameters binder = new BindOrganizationParameters();
+        OrganizationDto dto = new OrganizationDto();
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        binder.bindToRequest(request, dto);
+    }
+
+    public void testBindLogicServer()
+    {
+        BindOrganizationParameters binder = new BindOrganizationParameters();
+        OrganizationDto dto = new OrganizationDto();
+        dto.setDn("org");
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
+        HttpRequest newRequest = binder.bindToRequest(request, dto);
+        assertEquals(newRequest.getRequestLine(), "GET http://localhost?org=org HTTP/1.1");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/AbiquoComputeServiceLiveTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/AbiquoComputeServiceLiveTest.java
new file mode 100644
index 0000000..48d1f31
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/AbiquoComputeServiceLiveTest.java
@@ -0,0 +1,140 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute;
+
+import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
+import static org.testng.Assert.assertEquals;
+
+import java.util.Properties;
+
+import org.jclouds.Constants;
+import org.jclouds.compute.domain.ComputeType;
+import org.jclouds.compute.domain.ExecResponse;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.internal.BaseComputeServiceLiveTest;
+import org.jclouds.logging.config.LoggingModule;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Live tests for the Abiquo ComputeService.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "live", testName = "AbiquoComputeServiceLiveTest", singleThreaded = true)
+// Made abstract to avoid executing tests. Since the base class has test configuration, even if we
+// disable tests here, or comment them out, the ones in the base class will be executed
+public class AbiquoComputeServiceLiveTest extends BaseComputeServiceLiveTest
+{
+    public AbiquoComputeServiceLiveTest()
+    {
+        provider = "abiquo";
+    }
+
+    @Override
+    public void setServiceDefaults()
+    {
+        System
+            .setProperty("test.abiquo.template",
+                "imageNameMatches=ubuntu_server_ssh_iptables,loginUser=user:abiquo,authenticateSudo=true");
+    }
+
+    @Override
+    protected Properties setupProperties()
+    {
+        Properties overrides = super.setupProperties();
+        overrides.put(Constants.PROPERTY_MAX_RETRIES, "0");
+        overrides.put(Constants.PROPERTY_MAX_REDIRECTS, "0");
+        overrides.put("jclouds.timeouts.CloudApi.listVirtualMachines", "60000");
+        return overrides;
+    }
+
+    @Override
+    protected void initializeContext()
+    {
+        super.initializeContext();
+        String templateId = buildTemplate(client.templateBuilder()).getImage().getId();
+        view.getUtils().getCredentialStore().put("image#" + templateId, loginCredentials);
+    }
+
+    @Override
+    protected LoggingModule getLoggingModule()
+    {
+        return new SLF4JLoggingModule();
+    }
+
+    @Override
+    protected Module getSshModule()
+    {
+        return new SshjSshClientModule();
+    }
+
+    @Override
+    public void testListSizes() throws Exception
+    {
+        for (Hardware hardware : client.listHardwareProfiles())
+        {
+            assert hardware.getProviderId() != null : hardware;
+            assert getCores(hardware) > 0 : hardware;
+            assert hardware.getVolumes().size() >= 0 : hardware;
+            // There are some small images in Abiquo that have less than 1GB of RAM
+            // assert hardware.getRam() > 0 : hardware;
+            assertEquals(hardware.getType(), ComputeType.HARDWARE);
+        }
+    }
+
+    @Override
+    public void testOptionToNotBlock() throws Exception
+    {
+        // By default the provider blocks until the node is running
+    }
+
+    // Abiquo does not set the hostname
+    @Override
+    protected void checkResponseEqualsHostname(final ExecResponse execResponse,
+        final NodeMetadata node)
+    {
+        assert node.getHostname() == null : node + " with hostname: " + node.getHostname();
+    }
+
+    // Abiquo does not support metadata
+    @Override
+    protected void checkUserMetadataInNodeEquals(final NodeMetadata node,
+        final ImmutableMap<String, String> userMetadata)
+    {
+        assert node.getUserMetadata().equals(ImmutableMap.<String, String> of()) : String.format(
+            "node userMetadata did not match %s %s", userMetadata, node);
+    }
+
+    // Abiquo does not support tags
+    @Override
+    protected void checkTagsInNodeEquals(final NodeMetadata node, final ImmutableSet<String> tags)
+    {
+        assert node.getTags().equals(ImmutableSet.<String> of()) : String.format(
+            "node tags did not match %s %s", tags, node);
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/DatacenterToLocationTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/DatacenterToLocationTest.java
new file mode 100644
index 0000000..2edbc1f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/DatacenterToLocationTest.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LocationScope;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link DatacenterToLocation} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "DatacenterToLocationTest")
+public class DatacenterToLocationTest
+{
+    @SuppressWarnings("unchecked")
+    public void testDatacenterToLocation()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        DatacenterToLocation function = new DatacenterToLocation();
+
+        Datacenter datacenter = Datacenter.builder(context).name("dc").location("New York").build();
+        datacenter.unwrap().setId(5);
+        Location location = function.apply(datacenter);
+
+        assertEquals(location.getId(), "5");
+        assertEquals(location.getScope(), LocationScope.ZONE);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineStateToNodeStateTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineStateToNodeStateTest.java
new file mode 100644
index 0000000..ea31bbc
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineStateToNodeStateTest.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+
+/**
+ * Unit tests for the {@link VirtualMachineStateToNodeState} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "VirtualMachineStateToNodeStateTest")
+public class VirtualMachineStateToNodeStateTest
+{
+    public void testVirtualMachineStateToNodeState()
+    {
+        VirtualMachineStateToNodeState function = new VirtualMachineStateToNodeState();
+
+        assertEquals(function.apply(VirtualMachineState.ALLOCATED), Status.PENDING);
+        assertEquals(function.apply(VirtualMachineState.LOCKED), Status.PENDING);
+        assertEquals(function.apply(VirtualMachineState.CONFIGURED), Status.PENDING);
+        assertEquals(function.apply(VirtualMachineState.ON), Status.RUNNING);
+        assertEquals(function.apply(VirtualMachineState.OFF), Status.SUSPENDED);
+        assertEquals(function.apply(VirtualMachineState.PAUSED), Status.SUSPENDED);
+        assertEquals(function.apply(VirtualMachineState.NOT_ALLOCATED), Status.TERMINATED);
+        assertEquals(function.apply(VirtualMachineState.UNKNOWN), Status.UNRECOGNIZED);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToHardwareTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToHardwareTest.java
new file mode 100644
index 0000000..3c6d812
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToHardwareTest.java
@@ -0,0 +1,173 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import java.net.URI;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+
+/**
+ * Unit tests for the {@link VirtualMachineTemplateToHardware} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "VirtualMachineTemplateToHardwareTest")
+public class VirtualMachineTemplateToHardwareTest
+{
+    @SuppressWarnings("unchecked")
+    public void testVirtualMachineTemplateToHardware()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToHardware function = new VirtualMachineTemplateToHardware();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        dto.setId(5);
+        dto.setName("Template");
+        dto.setDescription("Template description");
+        dto.setHdRequired(50L * 1024 * 1024 * 1024); // 50 GB
+        dto.setCpuRequired(5);
+        dto.setRamRequired(2048);
+        dto.addLink(new RESTLink("edit", "http://foo/bar"));
+
+        Hardware hardware = function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+
+        assertEquals(hardware.getId(), dto.getId().toString());
+        assertEquals(hardware.getName(), dto.getName());
+        assertEquals(hardware.getUri(), URI.create("http://foo/bar"));
+
+        assertEquals(hardware.getRam(), dto.getRamRequired());
+        assertEquals(hardware.getProcessors().size(), 1);
+        assertEquals(hardware.getProcessors().get(0).getCores(), (double) dto.getCpuRequired());
+        assertEquals(hardware.getProcessors().get(0).getSpeed(),
+            VirtualMachineTemplateToHardware.DEFAULT_CORE_SPEED);
+
+        assertEquals(hardware.getVolumes().size(), 1);
+        assertEquals(hardware.getVolumes().get(0).getSize(), 50F);
+        assertEquals(hardware.getVolumes().get(0).getType(), Volume.Type.LOCAL);
+        assertEquals(hardware.getVolumes().get(0).isBootDevice(), true);
+        assertEquals(hardware.getVolumes().get(0).isDurable(), false);
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testConvertWithoutEditLink()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToHardware function = new VirtualMachineTemplateToHardware();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        dto.setId(5);
+        dto.setName("Template");
+        dto.setDescription("Template description");
+        dto.setHdRequired(50L * 1024 * 1024 * 1024); // 50 GB
+        dto.setCpuRequired(5);
+        dto.setRamRequired(2048);
+
+        Hardware hardware = function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+
+        assertNull(hardware.getUri());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testConvertWithoutId()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToHardware function = new VirtualMachineTemplateToHardware();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testConvertWithoutCpu()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToHardware function = new VirtualMachineTemplateToHardware();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        dto.setId(5);
+        dto.setName("Template");
+        dto.setDescription("Template description");
+        dto.setHdRequired(50L * 1024 * 1024 * 1024); // 50 GB
+        dto.setRamRequired(2048);
+
+        Hardware hardware = function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+
+        assertEquals(hardware.getProcessors().size(), 1);
+        assertEquals(hardware.getProcessors().get(0).getCores(), 0D);
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testConvertWithoutRam()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToHardware function = new VirtualMachineTemplateToHardware();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        dto.setId(5);
+        dto.setName("Template");
+        dto.setDescription("Template description");
+        dto.setHdRequired(50L * 1024 * 1024 * 1024); // 50 GB
+        dto.setCpuRequired(5);
+
+        Hardware hardware = function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+
+        assertEquals(hardware.getRam(), 0);
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testConvertWithoutHd()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToHardware function = new VirtualMachineTemplateToHardware();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        dto.setId(5);
+        dto.setName("Template");
+        dto.setDescription("Template description");
+        dto.setCpuRequired(5);
+        dto.setRamRequired(2048);
+
+        Hardware hardware = function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+
+        assertEquals(hardware.getVolumes().size(), 1);
+        assertEquals(hardware.getVolumes().get(0).getSize(), 0F);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToImageTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToImageTest.java
new file mode 100644
index 0000000..95e79e1
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineTemplateToImageTest.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import java.net.URI;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+
+/**
+ * Unit tests for the {@link VirtualMachineTemplateToImage} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "VirtualMachineTemplateToImageTest")
+public class VirtualMachineTemplateToImageTest
+{
+    @SuppressWarnings("unchecked")
+    public void testVirtualMachineTemplateToImage()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToImage function = new VirtualMachineTemplateToImage();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        dto.setId(5);
+        dto.setName("Template");
+        dto.setDescription("Template description");
+        dto.addLink(new RESTLink("diskfile", "http://foo/bar"));
+
+        Image image = function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+
+        assertEquals(image.getId(), dto.getId().toString());
+        assertEquals(image.getName(), dto.getName());
+        assertEquals(image.getDescription(), dto.getDescription());
+        assertEquals(image.getUri(), URI.create("http://foo/bar"));
+        assertEquals(image.getOperatingSystem(),
+            OperatingSystem.builder().description(dto.getName()).build());
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testConvertWithoutDownloadLink()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToImage function = new VirtualMachineTemplateToImage();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        dto.setId(5);
+        dto.setName("Template");
+        dto.setDescription("Template description");
+
+        Image image = function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+
+        assertNull(image.getUri());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testConvertWithoutId()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+        VirtualMachineTemplateToImage function = new VirtualMachineTemplateToImage();
+
+        // VirtualMachineTemplate domain object does not have a builder, it is read only
+        VirtualMachineTemplateDto dto = new VirtualMachineTemplateDto();
+        function.apply(wrap(context, VirtualMachineTemplate.class, dto));
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineToNodeMetadataTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineToNodeMetadataTest.java
new file mode 100644
index 0000000..d29b655
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/functions/VirtualMachineToNodeMetadataTest.java
@@ -0,0 +1,245 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.functions;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.ExternalIp;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PublicIp;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.domain.Location;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+/**
+ * Unit tests for the {@link VirtualMachineToNodeMetadata} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "VirtualMachineToNodeMetadataTest")
+public class VirtualMachineToNodeMetadataTest
+{
+    private VirtualMachineToNodeMetadata function;
+
+    private VirtualMachineWithNodeExtendedDto vm;
+
+    private PrivateIpDto privNic;
+
+    private PublicIpDto pubNic;
+
+    private ExternalIpDto extNic;
+
+    private Hardware hardware;
+
+    @BeforeMethod
+    public void setup()
+    {
+        vm = new VirtualMachineWithNodeExtendedDto();
+        vm.setNodeName("VM");
+        vm.setName("Internal name");
+        vm.setId(5);
+        vm.setVdrpPort(22);
+        vm.setRam(2048);
+        vm.setCpu(2);
+        vm.setState(VirtualMachineState.ON);
+        vm.addLink(new RESTLink("edit", "http://foo/bar"));
+
+        privNic = new PrivateIpDto();
+        privNic.setIp("192.168.1.2");
+        privNic.setMac("2a:6e:40:69:84:e0");
+
+        pubNic = new PublicIpDto();
+        pubNic.setIp("80.80.80.80");
+        pubNic.setMac("2a:6e:40:69:84:e1");
+
+        extNic = new ExternalIpDto();
+        extNic.setIp("10.10.10.10");
+        extNic.setMac("2a:6e:40:69:84:e2");
+
+        hardware = new HardwareBuilder() //
+            .ids("1") //
+            .build();
+
+        function =
+            new VirtualMachineToNodeMetadata(templateToImage(),
+                templateToHardware(),
+                stateToNodeState(),
+                datacenterToLocation());
+    }
+
+    public void testVirtualMachineToNodeMetadata()
+    {
+        VirtualAppliance vapp = EasyMock.createMock(VirtualAppliance.class);
+        VirtualMachine mockVm = mockVirtualMachine(vapp);
+
+        NodeMetadata node = function.apply(mockVm);
+
+        verify(mockVm);
+
+        assertEquals(node.getId(), vm.getId().toString());
+        assertEquals(node.getUri(), URI.create("http://foo/bar"));
+        assertEquals(node.getName(), vm.getNodeName());
+        assertEquals(node.getGroup(), "VAPP");
+        assertEquals(node.getLocation().getId(), "1");
+        assertEquals(node.getLocation().getDescription(), "Mock Location");
+        assertEquals(node.getImageId(), "1");
+        assertEquals(node.getHardware().getId(), "1");
+        assertEquals(node.getHardware().getHypervisor(), HypervisorType.VMX_04.name());
+        assertEquals(node.getHardware().getId(), "1");
+        assertEquals(node.getHardware().getRam(), vm.getRam());
+        assertEquals(node.getHardware().getProcessors().get(0).getCores(), (double) vm.getCpu());
+        assertEquals(node.getLoginPort(), vm.getVdrpPort());
+        assertEquals(node.getPrivateAddresses().size(), 1);
+        assertEquals(node.getPublicAddresses().size(), 2);
+        assertEquals(Iterables.get(node.getPrivateAddresses(), 0), privNic.getIp());
+        assertEquals(Iterables.get(node.getPublicAddresses(), 0), pubNic.getIp());
+        assertEquals(Iterables.get(node.getPublicAddresses(), 1), extNic.getIp());
+    }
+
+    private VirtualMachineTemplateToImage templateToImage()
+    {
+        VirtualMachineTemplateToImage templateToImage =
+            EasyMock.createMock(VirtualMachineTemplateToImage.class);
+        Image image = EasyMock.createMock(Image.class);
+
+        expect(image.getId()).andReturn("1");
+        expect(image.getOperatingSystem()).andReturn(null);
+        expect(templateToImage.apply(anyObject(VirtualMachineTemplate.class))).andReturn(image);
+
+        replay(image);
+        replay(templateToImage);
+
+        return templateToImage;
+    }
+
+    private VirtualMachineTemplateToHardware templateToHardware()
+    {
+        VirtualMachineTemplateToHardware virtualMachineTemplateToHardware =
+            EasyMock.createMock(VirtualMachineTemplateToHardware.class);
+
+        expect(virtualMachineTemplateToHardware.apply(anyObject(VirtualMachineTemplate.class)))
+            .andReturn(hardware);
+
+        replay(virtualMachineTemplateToHardware);
+
+        return virtualMachineTemplateToHardware;
+    }
+
+    private DatacenterToLocation datacenterToLocation()
+    {
+        DatacenterToLocation datacenterToLocation = EasyMock.createMock(DatacenterToLocation.class);
+        Location location = EasyMock.createMock(Location.class);
+
+        expect(location.getId()).andReturn("1");
+        expect(location.getDescription()).andReturn("Mock Location");
+
+        expect(datacenterToLocation.apply(anyObject(Datacenter.class))).andReturn(location);
+
+        replay(location);
+        replay(datacenterToLocation);
+
+        return datacenterToLocation;
+    }
+
+    private VirtualMachineStateToNodeState stateToNodeState()
+    {
+        VirtualMachineStateToNodeState stateToNodeState =
+            EasyMock.createMock(VirtualMachineStateToNodeState.class);
+        expect(stateToNodeState.apply(anyObject(VirtualMachineState.class))).andReturn(
+            Status.RUNNING);
+        replay(stateToNodeState);
+        return stateToNodeState;
+    }
+
+    private VirtualDatacenter mockVirtualDatacenter()
+    {
+        VirtualDatacenter vdc = EasyMock.createMock(VirtualDatacenter.class);
+        expect(vdc.getHypervisorType()).andReturn(HypervisorType.VMX_04);
+        expect(vdc.getDatacenter()).andReturn(null);
+        replay(vdc);
+        return vdc;
+    }
+
+    private VirtualMachineTemplate mockTemplate()
+    {
+        return EasyMock.createMock(VirtualMachineTemplate.class);
+    }
+
+    @SuppressWarnings("unchecked")
+    private VirtualMachine mockVirtualMachine(final VirtualAppliance vapp)
+    {
+        VirtualMachine mockVm = EasyMock.createMock(VirtualMachine.class);
+
+        Ip< ? , ? > mockPrivNic =
+            wrap(EasyMock.createMock(RestContext.class), PrivateIp.class, privNic);
+        Ip< ? , ? > mockPubNic =
+            wrap(EasyMock.createMock(RestContext.class), PublicIp.class, pubNic);
+        Ip< ? , ? > mockExtNic =
+            wrap(EasyMock.createMock(RestContext.class), ExternalIp.class, extNic);
+
+        expect(mockVm.getId()).andReturn(vm.getId());
+        expect(mockVm.getURI()).andReturn(URI.create(vm.getEditLink().getHref()));
+        expect(mockVm.getNameLabel()).andReturn(vm.getNodeName());
+        expect(mockVm.getTemplate()).andReturn(mockTemplate());
+        expect(mockVm.getState()).andReturn(vm.getState());
+        expect(mockVm.listAttachedNics()).andReturn(
+            ImmutableList.<Ip< ? , ? >> of(mockPubNic, mockPrivNic, mockExtNic));
+        expect(mockVm.getVirtualAppliance()).andReturn(vapp);
+        expect(vapp.getName()).andReturn("VAPP");
+        expect(mockVm.getVirtualDatacenter()).andReturn(mockVirtualDatacenter());
+        expect(mockVm.getRam()).andReturn(vm.getRam());
+        expect(mockVm.getCpu()).andReturn(vm.getCpu());
+
+        replay(mockVm);
+        replay(vapp);
+
+        return mockVm;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/options/AbiquoTemplateOptionsTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/options/AbiquoTemplateOptionsTest.java
new file mode 100644
index 0000000..7e8496f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/compute/options/AbiquoTemplateOptionsTest.java
@@ -0,0 +1,145 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.compute.options;
+
+import static org.jclouds.abiquo.domain.DomainWrapper.wrap;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PrivateNetwork;
+import org.jclouds.abiquo.domain.network.UnmanagedNetwork;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+
+/**
+ * Unit tests for the {@link AbiquoTemplateOptions} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AbiquoTemplateOptionsTest")
+public class AbiquoTemplateOptionsTest
+{
+    public void testAs()
+    {
+        TemplateOptions options = new AbiquoTemplateOptions();
+        assertEquals(options.as(AbiquoTemplateOptions.class), options);
+    }
+
+    public void testOverrideCores()
+    {
+        TemplateOptions options = new AbiquoTemplateOptions().overrideCores(5);
+        assertEquals(options.as(AbiquoTemplateOptions.class).getOverrideCores(), Integer.valueOf(5));
+    }
+
+    public void testOverrideRam()
+    {
+        TemplateOptions options = new AbiquoTemplateOptions().overrideRam(2048);
+        assertEquals(options.as(AbiquoTemplateOptions.class).getOverrideRam(),
+            Integer.valueOf(2048));
+    }
+
+    public void testVncPassword()
+    {
+        TemplateOptions options = new AbiquoTemplateOptions().vncPassword("foo");
+        assertEquals(options.as(AbiquoTemplateOptions.class).getVncPassword(), "foo");
+    }
+
+    public void testVirtualDatacenter()
+    {
+        TemplateOptions options = new AbiquoTemplateOptions().virtualDatacenter("foo");
+        assertEquals(options.as(AbiquoTemplateOptions.class).getVirtualDatacenter(), "foo");
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testIps()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+
+        PrivateIpDto dto1 = new PrivateIpDto();
+        dto1.setIp("10.60.0.1");
+        PrivateIpDto dto2 = new PrivateIpDto();
+        dto2.setIp("10.60.0.2");
+
+        PrivateIp ip1 = wrap(context, PrivateIp.class, dto1);
+        PrivateIp ip2 = wrap(context, PrivateIp.class, dto2);
+
+        TemplateOptions options = new AbiquoTemplateOptions().ips(ip1, ip2);
+
+        Ip< ? , ? >[] ips = options.as(AbiquoTemplateOptions.class).getIps();
+        assertNotNull(ips);
+        assertEquals(ips[0].getIp(), "10.60.0.1");
+        assertEquals(ips[1].getIp(), "10.60.0.2");
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testGatewayNetwork()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+
+        VLANNetworkDto dto = new VLANNetworkDto();
+        dto.setAddress("10.0.0.0");
+        dto.setMask(24);
+        dto.setGateway("10.0.0.1");
+        dto.setType(NetworkType.INTERNAL);
+
+        PrivateNetwork gateway = wrap(context, PrivateNetwork.class, dto);
+
+        TemplateOptions options = new AbiquoTemplateOptions().gatewayNetwork(gateway);
+        assertEquals(options.as(AbiquoTemplateOptions.class).getGatewayNetwork(), gateway);
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testUnmanagedIps()
+    {
+        RestContext<AbiquoApi, AbiquoAsyncApi> context = EasyMock.createMock(RestContext.class);
+
+        VLANNetworkDto dto1 = new VLANNetworkDto();
+        dto1.setAddress("10.0.0.0");
+        dto1.setMask(24);
+        dto1.setGateway("10.0.0.1");
+        dto1.setType(NetworkType.UNMANAGED);
+
+        VLANNetworkDto dto2 = new VLANNetworkDto();
+        dto2.setAddress("10.1.0.0");
+        dto2.setMask(24);
+        dto2.setGateway("10.1.0.1");
+        dto2.setType(NetworkType.UNMANAGED);
+
+        UnmanagedNetwork net1 = wrap(context, UnmanagedNetwork.class, dto1);
+        UnmanagedNetwork net2 = wrap(context, UnmanagedNetwork.class, dto2);
+
+        TemplateOptions options = new AbiquoTemplateOptions().unmanagedIps(net1, net2);
+
+        UnmanagedNetwork[] nets = options.as(AbiquoTemplateOptions.class).getUnmanagedIps();
+        assertNotNull(nets);
+        assertEquals(nets[0].getAddress(), "10.0.0.0");
+        assertEquals(nets[1].getAddress(), "10.1.0.0");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/config/SchedulerModuleTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/config/SchedulerModuleTest.java
new file mode 100644
index 0000000..c8ba73d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/config/SchedulerModuleTest.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.config;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.jclouds.Constants;
+import org.jclouds.abiquo.internal.BaseInjectionTest;
+import org.testng.annotations.Test;
+
+import com.google.inject.Key;
+import com.google.inject.name.Names;
+
+/**
+ * Unit tests for the {@link SchedulerModule} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "SchedulerModuleTest")
+public class SchedulerModuleTest extends BaseInjectionTest
+{
+    public void testScheduledExecutorIsProvided()
+    {
+        assertNotNull(injector.getInstance(Key.get(ScheduledExecutorService.class,
+            Names.named(Constants.PROPERTY_SCHEDULER_THREADS))));
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/AbiquoVersionLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/AbiquoVersionLiveApiTest.java
new file mode 100644
index 0000000..0219fb1
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/AbiquoVersionLiveApiTest.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.fail;
+
+import java.util.Properties;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.internal.BaseAbiquoLiveApiTest;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the Abiquo versioning support.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "AbiquoVersionLiveApiTest")
+public class AbiquoVersionLiveApiTest extends BaseAbiquoLiveApiTest
+{
+    @Override
+    protected Properties setupProperties()
+    {
+        Properties overrides = super.setupProperties();
+        overrides.setProperty("abiquo.api-version", "0.0");
+        return overrides;
+    }
+
+    public void testUnsupportedVersion()
+    {
+        try
+        {
+            view.getAdministrationService().getCurrentUser();
+            fail("Unsupported versions in mime types should not be allowed");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.NOT_ACCEPTABLE, "406-NOT-ACCEPTABLE");
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/AdminResources.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/AdminResources.java
new file mode 100644
index 0000000..ac5ae69
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/AdminResources.java
@@ -0,0 +1,216 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.domain.DomainUtils.link;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.enterprise.DatacenterLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.RoleDto;
+import com.abiquo.server.core.enterprise.UserDto;
+
+/**
+ * Enterprise domain utilities.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class AdminResources
+{
+    public static RoleDto rolePost()
+    {
+        RoleDto role = new RoleDto();
+        role.addLink(new RESTLink("privileges",
+            "http://localhost/api/admin/roles/1/action/privileges"));
+        role.setName("HAWAIAN_ADMIN");
+        return role;
+    }
+
+    public static RoleDto rolePut()
+    {
+        RoleDto role = rolePost();
+        role.setId(1);
+        role.addLink(new RESTLink("edit", "http://localhost/api/admin/roles/1"));
+
+        return role;
+    }
+
+    public static String rolePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<role>");
+        buffer.append(link("/admin/roles/1/action/privileges", "privileges"));
+        buffer.append("<blocked>false</blocked>");
+        buffer.append("<name>HAWAIAN_ADMIN</name>");
+        buffer.append("</role>");
+        return buffer.toString();
+    }
+
+    public static String rolePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<role>");
+        buffer.append(link("/admin/roles/1/action/privileges", "privileges"));
+        buffer.append(link("/admin/roles/1", "edit"));
+        buffer.append("<blocked>false</blocked>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>HAWAIAN_ADMIN</name>");
+        buffer.append("</role>");
+        return buffer.toString();
+    }
+
+    public static DatacenterLimitsDto datacenterLimitsPost()
+    {
+        DatacenterLimitsDto limits = new DatacenterLimitsDto();
+        limits.setCpuCountLimits(0, 0);
+        limits.setHdLimitsInMb(0, 0);
+        limits.setPublicIPLimits(0, 0);
+        limits.setRamLimitsInMb(0, 0);
+        limits.setStorageLimits(0, 0);
+        limits.setVlansLimits(0, 0);
+        limits.setRepositoryHardLimitsInMb(0);
+        limits.setRepositorySoftLimitsInMb(0);
+        return limits;
+    }
+
+    public static DatacenterLimitsDto datacenterLimitsPut(final EnterpriseDto enterprise)
+    {
+        DatacenterLimitsDto limits = datacenterLimitsPost();
+        limits.setId(1);
+        limits.addLink(new RESTLink("edit", "http://localhost/api/admin/enterprises/"
+            + enterprise.getId() + "/limits/1"));
+        return limits;
+    }
+
+    public static String datacenterLimitsPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<limit>");
+        buffer.append("<cpuHard>0</cpuHard>");
+        buffer.append("<cpuSoft>0</cpuSoft>");
+        buffer.append("<hdHard>0</hdHard>");
+        buffer.append("<hdSoft>0</hdSoft>");
+        buffer.append("<publicIpsHard>0</publicIpsHard>");
+        buffer.append("<publicIpsSoft>0</publicIpsSoft>");
+        buffer.append("<ramHard>0</ramHard>");
+        buffer.append("<ramSoft>0</ramSoft>");
+        buffer.append("<storageHard>0</storageHard>");
+        buffer.append("<storageSoft>0</storageSoft>");
+        buffer.append("<vlansHard>0</vlansHard>");
+        buffer.append("<vlansSoft>0</vlansSoft>");
+        buffer.append("<repositoryHard>0</repositoryHard>");
+        buffer.append("<repositorySoft>0</repositorySoft>");
+        buffer.append("</limit>");
+        return buffer.toString();
+    }
+
+    public static String datacenterLimitsPutPayload(final EnterpriseDto enterprise)
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<limit>");
+        buffer.append(link("/admin/enterprises/" + enterprise.getId() + "/limits/1", "edit"));
+        buffer.append("<cpuHard>0</cpuHard>");
+        buffer.append("<cpuSoft>0</cpuSoft>");
+        buffer.append("<hdHard>0</hdHard>");
+        buffer.append("<hdSoft>0</hdSoft>");
+        buffer.append("<publicIpsHard>0</publicIpsHard>");
+        buffer.append("<publicIpsSoft>0</publicIpsSoft>");
+        buffer.append("<ramHard>0</ramHard>");
+        buffer.append("<ramSoft>0</ramSoft>");
+        buffer.append("<storageHard>0</storageHard>");
+        buffer.append("<storageSoft>0</storageSoft>");
+        buffer.append("<vlansHard>0</vlansHard>");
+        buffer.append("<vlansSoft>0</vlansSoft>");
+        buffer.append("<id>1</id>");
+        buffer.append("<repositoryHard>0</repositoryHard>");
+        buffer.append("<repositorySoft>0</repositorySoft>");
+        buffer.append("</limit>");
+        return buffer.toString();
+    }
+
+    public static String userPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<user>");
+        buffer.append(link("/admin/roles/1", "role"));
+        buffer.append("<active>true</active>");
+        buffer.append("<authType>ABIQUO</authType>");
+        buffer.append("<description>A hawaian user</description>");
+        buffer.append("<email>abe.joha@aloha.com</email>");
+        buffer.append("<locale>en_US</locale>");
+        buffer.append("<name>Aberahama</name>");
+        buffer.append("<nick>abejo</nick>");
+        buffer.append("<password>c69a39bd64ffb77ea7ee3369dce742f3</password>");
+        buffer.append("<surname>Johanson</surname>");
+        buffer.append("</user>");
+        return buffer.toString();
+    }
+
+    public static UserDto userPost()
+    {
+        UserDto user = new UserDto();
+        user.setName("Aberahama");
+        user.setSurname("Johanson");
+        user.setDescription("A hawaian user");
+        user.setEmail("abe.joha@aloha.com");
+        user.setNick("abejo");
+        user.setAuthType("ABIQUO");
+        user.setLocale("en_US");
+        user.setActive(true);
+        user.setPassword("c69a39bd64ffb77ea7ee3369dce742f3");
+        user.addLink(new RESTLink("role", "http://localhost/api/admin/roles/1"));
+        return user;
+    }
+
+    public static String userPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<user>");
+        buffer.append(link("/admin/roles/1", "role"));
+        buffer.append(link("/admin/enterprises/1/users/1", "edit"));
+        buffer.append(link("/admin/enterprises/1", "enterprise"));
+        buffer
+            .append(link("/admin/enterprises/1/users/1/action/virtualmachines", "virtualmachines"));
+        buffer.append("<active>true</active>");
+        buffer.append("<authType>ABIQUO</authType>");
+        buffer.append("<description>A hawaian user</description>");
+        buffer.append("<email>abe.joha@aloha.com</email>");
+        buffer.append("<id>1</id>");
+        buffer.append("<locale>en_US</locale>");
+        buffer.append("<name>Aberahama</name>");
+        buffer.append("<nick>abejo</nick>");
+        buffer.append("<password>c69a39bd64ffb77ea7ee3369dce742f3</password>");
+        buffer.append("<surname>Johanson</surname>");
+        buffer.append("</user>");
+        return buffer.toString();
+    }
+
+    public static UserDto userPut()
+    {
+        UserDto user = userPost();
+        user.setId(1);
+        user.addLink(new RESTLink("edit", "http://localhost/api/admin/enterprises/1/users/1"));
+        user.addLink(new RESTLink("enterprise", "http://localhost/api/admin/enterprises/1"));
+        user.addLink(new RESTLink("virtualmachines",
+            "http://localhost/api/admin/enterprises/1/users/1/action/virtualmachines"));
+        return user;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/CloudResources.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/CloudResources.java
new file mode 100644
index 0000000..b605f9f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/CloudResources.java
@@ -0,0 +1,529 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.domain.DomainUtils.link;
+
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.VolumeState;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.cloud.VirtualMachineDto;
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.abiquo.server.core.cloud.VirtualMachineStateDto;
+import com.abiquo.server.core.cloud.VirtualMachineTaskDto;
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+
+/**
+ * Cloud domain utilities.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class CloudResources
+{
+    public static VirtualDatacenterDto virtualDatacenterPost()
+    {
+        VirtualDatacenterDto virtualDatacenter = new VirtualDatacenterDto();
+        virtualDatacenter.setName("VDC");
+        virtualDatacenter.setHypervisorType(HypervisorType.KVM);
+        virtualDatacenter.setVlan(NetworkResources.vlanPost());
+        return virtualDatacenter;
+    }
+
+    public static VirtualApplianceDto virtualAppliancePost()
+    {
+        VirtualApplianceDto virtualAppliance = new VirtualApplianceDto();
+        virtualAppliance.setName("VA");
+        return virtualAppliance;
+    }
+
+    public static VirtualMachineDto virtualMachinePost()
+    {
+        VirtualMachineDto virtualMachine = new VirtualMachineDto();
+        virtualMachine.setName("VM");
+        return virtualMachine;
+    }
+
+    public static VirtualDatacenterDto virtualDatacenterPut()
+    {
+        VirtualDatacenterDto virtualDatacenter = virtualDatacenterPost();
+        virtualDatacenter.setId(1);
+        virtualDatacenter.addLink(new RESTLink("datacenter",
+            "http://localhost/api/admin/datacenters/1"));
+        virtualDatacenter.addLink(new RESTLink("disks",
+            "http://localhost/api/cloud/virtualdatacenters/1/disks"));
+        virtualDatacenter.addLink(new RESTLink("enterprise",
+            "http://localhost/api/admin/enterprises/1"));
+        virtualDatacenter.addLink(new RESTLink("edit",
+            "http://localhost/api/cloud/virtualdatacenters/1"));
+        virtualDatacenter.addLink(new RESTLink("tiers",
+            "http://localhost/api/cloud/virtualdatacenters/1/tiers"));
+        virtualDatacenter.addLink(new RESTLink("virtualappliances",
+            "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances"));
+        virtualDatacenter.addLink(new RESTLink("volumes",
+            "http://localhost/api/cloud/virtualdatacenters/1/volumes"));
+        virtualDatacenter.addLink(new RESTLink("privatenetworks",
+            "http://localhost/api/cloud/virtualdatacenters/1/privatenetworks"));
+        virtualDatacenter.addLink(new RESTLink("defaultnetwork",
+            "http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1"));
+        virtualDatacenter.addLink(new RESTLink("defaultvlan",
+            "http://localhost/api/cloud/virtualdatacenters/1/action/defaultvlan"));
+        virtualDatacenter.addLink(new RESTLink("topurchase",
+            "http://localhost/api/cloud/virtualdatacenters/1/publicips/topurchase"));
+        virtualDatacenter.addLink(new RESTLink("purchased",
+            "http://localhost/api/cloud/virtualdatacenters/1/publicips/purchased"));
+        virtualDatacenter.addLink(new RESTLink("templates",
+            "http://localhost/api/cloud/virtualdatacenters/1/action/templates"));
+        return virtualDatacenter;
+
+    }
+
+    public static VirtualApplianceDto virtualAppliancePut()
+    {
+        VirtualApplianceDto virtualAppliance = virtualAppliancePost();
+        virtualAppliance.setId(1);
+        virtualAppliance.addLink(new RESTLink("virtualdatacenter",
+            "http://localhost/api/cloud/virtualdatacenters/1"));
+        virtualAppliance.addLink(new RESTLink("deploy",
+            "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/action/deploy"));
+        virtualAppliance.addLink(new RESTLink("edit",
+            "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1"));
+        virtualAppliance.addLink(new RESTLink("state",
+            "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/state"));
+        virtualAppliance.addLink(new RESTLink("undeploy",
+            "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/action/undeploy"));
+        virtualAppliance.addLink(new RESTLink("virtualmachines",
+            "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines"));
+        return virtualAppliance;
+    }
+
+    public static VirtualMachineDto virtualMachinePut()
+    {
+        VirtualMachineDto virtualMachine = virtualMachinePost();
+        virtualMachine.setId(1);
+        virtualMachine
+            .addLink(new RESTLink("deploy",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/deploy"));
+        virtualMachine
+            .addLink(new RESTLink("disks",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/disks"));
+        virtualMachine
+            .addLink(new RESTLink("edit",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1"));
+        virtualMachine
+            .addLink(new RESTLink("state",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/state"));
+        virtualMachine
+            .addLink(new RESTLink("reset",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/reset"));
+        virtualMachine
+            .addLink(new RESTLink("tasks",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/tasks"));
+        virtualMachine
+            .addLink(new RESTLink("undeploy",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/undeploy"));
+        virtualMachine
+            .addLink(new RESTLink("persistent",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/persistent"));
+        virtualMachine.addLink(new RESTLink("virtualappliance",
+            "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1"));
+        virtualMachine
+            .addLink(new RESTLink("virtualmachinetemplate",
+                "http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1"));
+        virtualMachine
+            .addLink(new RESTLink("nics",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/network/nics"));
+        virtualMachine
+            .addLink(new RESTLink("volumes",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/volumes"));
+        virtualMachine
+            .addLink(new RESTLink("configurations",
+                "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/network/configurations"));
+        return virtualMachine;
+    }
+
+    public static VirtualMachineStateDto virtualMachineState()
+    {
+        VirtualMachineStateDto state = new VirtualMachineStateDto();
+        state.setState(VirtualMachineState.ON);
+        return state;
+    }
+
+    public static String virtualMachineStatePayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualmachinestate>");
+        buffer.append("<state>ON</state>");
+        buffer.append("</virtualmachinestate>");
+        return buffer.toString();
+    }
+
+    public static VolumeManagementDto volumePost()
+    {
+        VolumeManagementDto volume = new VolumeManagementDto();
+        volume.setName("Volume");
+        volume.setSizeInMB(1024);
+        volume.addLink(new RESTLink("tier",
+            "http://localhost/api/cloud/virtualdatacenters/1/tiers/1"));
+        return volume;
+    }
+
+    public static VolumeManagementDto volumePut()
+    {
+        VolumeManagementDto volume = volumePost();
+        volume.setId(1);
+        volume.setState(VolumeState.DETACHED.name());
+
+        volume.getLinks().clear();
+
+        RESTLink mappings =
+            new RESTLink("action",
+                "http://localhost/api/cloud/virtualdatacenters/1/volumes/1/action/initiatormappings");
+        mappings.setTitle("initiator mappings");
+        volume.addLink(mappings);
+        volume.addLink(new RESTLink("edit",
+            "http://localhost/api/cloud/virtualdatacenters/1/volumes/1"));
+        volume.addLink(new RESTLink("tier",
+            "http://localhost/api/cloud/virtualdatacenters/1/tiers/1"));
+        volume.addLink(new RESTLink("virtualdatacenter",
+            "http://localhost/api/cloud/virtualdatacenters/1"));
+        return volume;
+    }
+
+    public static VirtualMachineTemplateDto virtualMachineTemplatePut()
+    {
+        VirtualMachineTemplateDto template = new VirtualMachineTemplateDto();
+        template.setId(10);
+        template.setName("m0n0wall");
+        template.setDiskFormatType(DiskFormatType.VMDK_FLAT.toString());
+        template.setPath("1/abiquo-repository.abiquo.com/m0n0wall/m0n0wall-1.3b18-i386-flat.vmdk");
+        template.setDiskFileSize(27262976);
+        template.setCpuRequired(1);
+        template.setRamRequired(128);
+        template.setCpuRequired(27262976);
+        template.setCreationUser("SYSTEM");
+        template
+            .setIconUrl("http://ww1.prweb.com/prfiles/2010/08/02/2823234/gI_0_HakunaLogoMedium.jpg");
+        template.addLink(new RESTLink("icon", "http://localhost/api/config/icons/1"));
+        template.addLink(new RESTLink("category", "http://localhost/api/config/categories/1"));
+
+        return template;
+
+    }
+
+    public static TierDto cloudTierPut()
+    {
+        TierDto tier = new TierDto();
+        tier.setId(1);
+        tier.setEnabled(true);
+        tier.setName("Tier");
+        tier.addLink(new RESTLink("edit", "http://localhost/api/cloud/virtualdatacenters/1/tiers/1"));
+        return tier;
+    }
+
+    public static VirtualMachineTaskDto deployOptions()
+    {
+        VirtualMachineTaskDto deploy = new VirtualMachineTaskDto();
+        deploy.setForceEnterpriseSoftLimits(false);
+        return deploy;
+
+    }
+
+    public static VirtualMachineTaskDto undeployOptions()
+    {
+        VirtualMachineTaskDto deploy = new VirtualMachineTaskDto();
+        deploy.setForceUndeploy(true);
+        return deploy;
+    }
+
+    public static String virtualDatacenterPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualDatacenter>");
+        buffer.append("<cpuHard>0</cpuHard>");
+        buffer.append("<cpuSoft>0</cpuSoft>");
+        buffer.append("<hdHard>0</hdHard>");
+        buffer.append("<hdSoft>0</hdSoft>");
+        buffer.append("<publicIpsHard>0</publicIpsHard>");
+        buffer.append("<publicIpsSoft>0</publicIpsSoft>");
+        buffer.append("<ramHard>0</ramHard>");
+        buffer.append("<ramSoft>0</ramSoft>");
+        buffer.append("<storageHard>0</storageHard>");
+        buffer.append("<storageSoft>0</storageSoft>");
+        buffer.append("<vlansHard>0</vlansHard>");
+        buffer.append("<vlansSoft>0</vlansSoft>");
+        buffer.append("<hypervisorType>KVM</hypervisorType>");
+        buffer.append("<name>VDC</name>");
+        buffer.append(NetworkResources.vlanNetworkPostPayload());
+        buffer.append("</virtualDatacenter>");
+        return buffer.toString();
+    }
+
+    public static String virtualAppliancePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualAppliance>");
+        buffer.append("<error>0</error>");
+        buffer.append("<highDisponibility>0</highDisponibility>");
+        buffer.append("<name>VA</name>");
+        buffer.append("<publicApp>0</publicApp>");
+        buffer.append("</virtualAppliance>");
+        return buffer.toString();
+    }
+
+    public static String virtualMachinePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualMachine>");
+        buffer.append("<cpu>0</cpu>");
+        buffer.append("<hdInBytes>0</hdInBytes>");
+        buffer.append("<highDisponibility>0</highDisponibility>");
+        buffer.append("<idState>0</idState>");
+        buffer.append("<idType>0</idType>");
+        buffer.append("<name>VM</name>");
+        buffer.append("<ram>0</ram>");
+        buffer.append("<vdrpPort>0</vdrpPort>");
+        buffer.append("</virtualMachine>");
+        return buffer.toString();
+    }
+
+    public static String virtualDatacenterPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualDatacenter>");
+        buffer.append(link("/admin/datacenters/1", "datacenter"));
+        buffer.append(link("/cloud/virtualdatacenters/1/disks", "disks"));
+        buffer.append(link("/admin/enterprises/1", "enterprise"));
+        buffer.append(link("/cloud/virtualdatacenters/1", "edit"));
+        buffer.append(link("/cloud/virtualdatacenters/1/tiers", "tiers"));
+        buffer.append(link("/cloud/virtualdatacenters/1/virtualappliances", "virtualappliances"));
+        buffer.append(link("/cloud/virtualdatacenters/1/volumes", "volumes"));
+        buffer.append(link("/cloud/virtualdatacenters/1/privatenetworks", "privatenetworks"));
+        buffer.append(link("/cloud/virtualdatacenters/1/privatenetworks/1", "defaultnetwork"));
+        buffer.append(link("/cloud/virtualdatacenters/1/action/defaultvlan", "defaultvlan"));
+        buffer.append(link("/cloud/virtualdatacenters/1/publicips/topurchase", "topurchase"));
+        buffer.append(link("/cloud/virtualdatacenters/1/publicips/purchased", "purchased"));
+        buffer.append(link("/cloud/virtualdatacenters/1/action/templates", "templates"));
+        buffer.append("<cpuHard>0</cpuHard>");
+        buffer.append("<cpuSoft>0</cpuSoft>");
+        buffer.append("<hdHard>0</hdHard>");
+        buffer.append("<hdSoft>0</hdSoft>");
+        buffer.append("<publicIpsHard>0</publicIpsHard>");
+        buffer.append("<publicIpsSoft>0</publicIpsSoft>");
+        buffer.append("<ramHard>0</ramHard>");
+        buffer.append("<ramSoft>0</ramSoft>");
+        buffer.append("<storageHard>0</storageHard>");
+        buffer.append("<storageSoft>0</storageSoft>");
+        buffer.append("<vlansHard>0</vlansHard>");
+        buffer.append("<vlansSoft>0</vlansSoft>");
+        buffer.append("<hypervisorType>KVM</hypervisorType>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>VDC</name>");
+        buffer.append(NetworkResources.vlanNetworkPostPayload());
+        buffer.append("</virtualDatacenter>");
+        return buffer.toString();
+    }
+
+    public static String virtualDatacenterRefPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<links>");
+        buffer.append(link("/cloud/virtualdatacenters/1", "virtualdatacenter"));
+        buffer.append("</links>");
+        return buffer.toString();
+    }
+
+    public static String virtualAppliancePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualAppliance>");
+        buffer.append(link("/cloud/virtualdatacenters/1", "virtualdatacenter"));
+        buffer.append(link("/cloud/virtualdatacenters/1/virtualappliances/1/action/deploy",
+            "deploy"));
+        buffer.append(link("/cloud/virtualdatacenters/1/virtualappliances/1", "edit"));
+        buffer.append(link("/cloud/virtualdatacenters/1/virtualappliances/1/state", "state"));
+        buffer.append(link("/cloud/virtualdatacenters/1/virtualappliances/1/action/undeploy",
+            "undeploy"));
+        buffer.append(link("/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines",
+            "virtualmachines"));
+        buffer.append("<error>0</error>");
+        buffer.append("<highDisponibility>0</highDisponibility>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>VA</name>");
+        buffer.append("<publicApp>0</publicApp>");
+        buffer.append("</virtualAppliance>");
+        return buffer.toString();
+    }
+
+    public static String virtualMachinePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualMachine>");
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/deploy",
+            "deploy"));
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/disks",
+            "disks"));
+        buffer.append(link("/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1",
+            "edit"));
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/state", "state"));
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/reset",
+            "reset"));
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/tasks", "tasks"));
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/undeploy",
+            "undeploy"));
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/persistent",
+            "persistent"));
+        buffer.append(link("/cloud/virtualdatacenters/1/virtualappliances/1", "virtualappliance"));
+        buffer.append(link(
+            "/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1",
+            "virtualmachinetemplate"));
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/network/nics",
+            "nics"));
+        buffer.append(link(
+            "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/volumes",
+            "volumes"));
+        buffer
+            .append(link(
+                "/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/network/configurations",
+                "configurations"));
+
+        buffer.append("<cpu>0</cpu>");
+        buffer.append("<hdInBytes>0</hdInBytes>");
+        buffer.append("<highDisponibility>0</highDisponibility>");
+        buffer.append("<id>1</id>");
+        buffer.append("<idState>0</idState>");
+        buffer.append("<idType>0</idType>");
+        buffer.append("<name>VM</name>");
+        buffer.append("<ram>0</ram>");
+        buffer.append("<vdrpPort>0</vdrpPort>");
+        buffer.append("</virtualMachine>");
+        return buffer.toString();
+    }
+
+    public static String volumePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<volume>");
+        buffer.append(link("/cloud/virtualdatacenters/1/tiers/1", "tier"));
+        buffer.append("<name>Volume</name>");
+        buffer.append("<sizeInMB>1024</sizeInMB>");
+        buffer.append("</volume>");
+        return buffer.toString();
+    }
+
+    public static String volumePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<volume>");
+        buffer.append(link("/cloud/virtualdatacenters/1/volumes/1/action/initiatormappings",
+            "action", "initiator mappings"));
+        buffer.append(link("/cloud/virtualdatacenters/1/volumes/1", "edit"));
+        buffer.append(link("/cloud/virtualdatacenters/1/tiers/1", "tier"));
+        buffer.append(link("/cloud/virtualdatacenters/1", "virtualdatacenter"));
+        buffer.append("<id>1</id>");
+        buffer.append("<name>Volume</name>");
+        buffer.append("<state>DETACHED</state>");
+        buffer.append("<sizeInMB>1024</sizeInMB>");
+        buffer.append("</volume>");
+        return buffer.toString();
+    }
+
+    public static String cloudTierPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<tier>");
+        buffer.append(link("/cloud/virtualdatacenters/1/tiers/1", "edit"));
+        buffer.append("<enabled>true</enabled>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>Tier</name>");
+        buffer.append("</tier>");
+        return buffer.toString();
+    }
+
+    public static String deployPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualmachinetask>");
+        buffer.append("<forceEnterpriseSoftLimits>false</forceEnterpriseSoftLimits>");
+        buffer.append("</virtualmachinetask>");
+        return buffer.toString();
+    }
+
+    public static String undeployPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualmachinetask>");
+        buffer.append("<forceEnterpriseSoftLimits>false</forceEnterpriseSoftLimits>");
+        buffer.append("<forceUndeploy>true</forceUndeploy>");
+        buffer.append("</virtualmachinetask>");
+        return buffer.toString();
+    }
+
+    public static DiskManagementDto hardDiskPost()
+    {
+        DiskManagementDto disk = new DiskManagementDto();
+        disk.setSizeInMb(1024L);
+        return disk;
+    }
+
+    public static DiskManagementDto hardDiskPut()
+    {
+        DiskManagementDto disk = hardDiskPost();
+        disk.addLink(new RESTLink("edit", "http://localhost/api/cloud/virtualdatacenters/1/disks/1"));
+        disk.addLink(new RESTLink("virtualdatacenter",
+            "http://localhost/api/cloud/virtualdatacenters/1"));
+        return disk;
+    }
+
+    public static String hardDiskPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<disk>");
+        buffer.append("<sizeInMb>1024</sizeInMb>");
+        buffer.append("</disk>");
+        return buffer.toString();
+    }
+
+    public static String hardDiskPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<disk>");
+        buffer.append(link("/cloud/virtualdatacenters/1", "virtualdatacenter"));
+        buffer.append(link("/cloud/virtualdatacenters/1/disks/1", "edit"));
+        buffer.append("<sequence>0</sequence>");
+        buffer.append("<sizeInMb>1024</sizeInMb>");
+        buffer.append("</disk>");
+        return buffer.toString();
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/ConfigResources.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/ConfigResources.java
new file mode 100644
index 0000000..f3df449
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/ConfigResources.java
@@ -0,0 +1,182 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.domain.DomainUtils.link;
+
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.Charset;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.appslibrary.CategoryDto;
+import com.abiquo.server.core.config.LicenseDto;
+import com.abiquo.server.core.config.SystemPropertyDto;
+import com.google.common.io.Resources;
+
+/**
+ * Enterprise domain utilities.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class ConfigResources
+{
+    public static LicenseDto licensePost()
+    {
+        LicenseDto license = new LicenseDto();
+        license.setCode(readLicense("license/expired"));
+        license.setCustomerid("3bca6d1d-5fe2-42c5-82ea-a5276ea8c71c");
+        return license;
+    }
+
+    public static CategoryDto categoryPost()
+    {
+        CategoryDto category = new CategoryDto();
+        category.setName("category");
+        category.setErasable(false);
+        category.setDefaultCategory(false);
+        return category;
+    }
+
+    public static CategoryDto categoryPut()
+    {
+        CategoryDto category = categoryPost();
+        category.setId(1);
+        category.addLink(new RESTLink("edit", "http://localhost/api/config/categories/1"));
+        return category;
+    }
+
+    public static LicenseDto licensePut()
+    {
+        LicenseDto license = licensePost();
+        license.setId(1);
+        license.addLink(new RESTLink("edit", "http://localhost/api/config/licenses/1"));
+
+        return license;
+    }
+
+    public static SystemPropertyDto propertyPut()
+    {
+        SystemPropertyDto property = new SystemPropertyDto();
+        property.setId(1);
+        property.setDescription("Time interval in seconds");
+        property.setValue("10");
+        property.setName("api.applibrary.ovfpackagesDownloadingProgressUpdateInterval");
+        property.addLink(new RESTLink("edit", "http://localhost/api/config/properties/1"));
+
+        return property;
+    }
+
+    public static String licensePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<license>");
+        buffer.append(link("/admin/enterprises/config/licenses/1", "edit"));
+        buffer.append("<customerid>3bca6d1d-5fe2-42c5-82ea-a5276ea8c71c</customerid>");
+        buffer.append("<code>" + readLicense("license/expired") + "</code>");
+        buffer.append("<id>1</id>");
+        buffer.append("</license>");
+        return buffer.toString();
+    }
+
+    public static String licensePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<license>");
+        buffer.append("<customerid>3bca6d1d-5fe2-42c5-82ea-a5276ea8c71c</customerid>");
+        buffer.append("<code>" + readLicense("license/expired") + "</code>");
+        buffer.append("</license>");
+        return buffer.toString();
+    }
+
+    public static String categoryPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<category>");
+        buffer.append("<defaultCategory>false</defaultCategory>");
+        buffer.append("<erasable>false</erasable>");
+        buffer.append("<name>category</name>");
+        buffer.append("</category>");
+        return buffer.toString();
+    }
+
+    public static String categoryPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<category>");
+        buffer.append(link("/config/categories/1", "edit"));
+        buffer.append("<defaultCategory>false</defaultCategory>");
+        buffer.append("<erasable>false</erasable>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>category</name>");
+        buffer.append("</category>");
+        return buffer.toString();
+    }
+
+    public static String iconPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<icon>");
+        buffer.append(link("/config/icons/1", "edit"));
+        buffer.append("<id>1</id>");
+        buffer.append("<name>icon</name>");
+        buffer.append("<path>http://www.pixeljoint.com/files/icons/mipreview1.gif</path>");
+        buffer.append("</icon>");
+        return buffer.toString();
+    }
+
+    public static String iconPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<icon>");
+        buffer.append("<name>icon</name>");
+        buffer.append("<path>http://www.pixeljoint.com/files/icons/mipreview1.gif</path>");
+        buffer.append("</icon>");
+        return buffer.toString();
+    }
+
+    public static String propertyPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<property>");
+        buffer.append(link("/config/properties/1", "edit"));
+        buffer.append("<description>Time interval in seconds</description>");
+        buffer.append("<id>1</id>");
+        buffer
+            .append("<name>api.applibrary.ovfpackagesDownloadingProgressUpdateInterval</name>");
+        buffer.append("<value>10</value>");
+        buffer.append("</property>");
+        return buffer.toString();
+    }
+
+    private static String readLicense(final String filename)
+    {
+        URL url = ConfigResources.class.getResource("/" + filename);
+        try
+        {
+            return Resources.toString(url, Charset.defaultCharset());
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException("Could not read file " + filename);
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/DomainUtils.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/DomainUtils.java
new file mode 100644
index 0000000..88e3092
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/DomainUtils.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import org.jclouds.xml.XMLParser;
+
+import com.abiquo.model.rest.RESTLink;
+
+/**
+ * Utility class to build domain objects used in tests.
+ * 
+ * @author Ignasi Barrera
+ */
+public class DomainUtils
+{
+    /**
+     * Adds the XML header to the given XML.
+     */
+    public static String withHeader(final String xml)
+    {
+        return XMLParser.DEFAULT_XML_HEADER + xml;
+    }
+
+    /**
+     * Builds a link in xml format
+     */
+    public static String link(final String href, final String rel)
+    {
+        return "<link href=\"http://localhost/api" + href + "\" rel=\"" + rel + "\"/>";
+    }
+
+    /**
+     * Builds a link in xml format
+     */
+    public static String link(final String href, final String rel, final String title)
+    {
+        return "<link href=\"http://localhost/api" + href + "\" rel=\"" + rel + "\" title=\""
+            + title + "\"/>";
+    }
+
+    /**
+     * Builds a link in xml format
+     */
+    public static String link(final RESTLink link)
+    {
+        return "<link href=\"" + link.getHref() + "\" rel=\"" + link.getRel() + "\""
+            + (link.getTitle() == null ? "" : " title=\"" + link.getTitle() + "\"") + "/>";
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/EnterpriseResources.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/EnterpriseResources.java
new file mode 100644
index 0000000..6dc496b
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/EnterpriseResources.java
@@ -0,0 +1,353 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.domain.DomainUtils.link;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListDto;
+import com.abiquo.server.core.enterprise.DatacenterLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.EnterprisePropertiesDto;
+import com.abiquo.server.core.enterprise.UserDto;
+
+/**
+ * Enterprise domain utilities.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class EnterpriseResources
+{
+    public static EnterpriseDto enterprisePost()
+    {
+        EnterpriseDto enterprise = new EnterpriseDto();
+        enterprise.setName("Kalakaua");
+        return enterprise;
+    }
+
+    public static EnterpriseDto enterprisePut()
+    {
+        EnterpriseDto enterprise = enterprisePost();
+        enterprise.setId(1);
+        enterprise.addLink(new RESTLink("edit", "http://localhost/api/admin/enterprises/1"));
+        enterprise
+            .addLink(new RESTLink("limits", "http://localhost/api/admin/enterprises/1/limits"));
+        enterprise.addLink(new RESTLink("users", "http://localhost/api/admin/enterprises/1/users"));
+        enterprise.addLink(new RESTLink("properties",
+            "http://localhost/api/admin/enterprises/1/properties"));
+        enterprise.addLink(new RESTLink("reservedmachines",
+            "http://localhost/api/admin/enterprises/1/reservedmachines"));
+        enterprise.addLink(new RESTLink("datacenterrepositories",
+            "http://localhost/api/admin/enterprises/1/datacenterrepositories"));
+        enterprise.addLink(new RESTLink("externalnetworks",
+            "http://localhost/api/admin/enterprises/1/action/externalnetworks"));
+        enterprise.addLink(new RESTLink("virtualmachines",
+            "http://localhost/api/admin/enterprises/1/action/virtualmachines"));
+        enterprise.addLink(new RESTLink("cloud/virtualdatacenters",
+            "http://localhost/api/admin/enterprises/1/action/virtualdatacenters"));
+        enterprise.addLink(new RESTLink("virtualappliances",
+            "http://localhost/api/admin/enterprises/1/action/virtualappliances"));
+        enterprise.addLink(new RESTLink("appslib/templateDefinitionLists",
+            "http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists"));
+
+        return enterprise;
+    }
+
+    public static EnterprisePropertiesDto enterprisePropertiesPut()
+    {
+        EnterprisePropertiesDto enterpriseProp = new EnterprisePropertiesDto();
+        enterpriseProp.setId(1);
+        Map<String, String> props = new HashMap<String, String>();
+        props.put("key", "value");
+        enterpriseProp.setProperties(props);
+        enterpriseProp.addLink(new RESTLink("edit",
+            "http://localhost/api/admin/enterprises/1/properties"));
+        enterpriseProp.addLink(new RESTLink("enterprise",
+            "http://localhost/api/admin/enterprises/1"));
+
+        return enterpriseProp;
+    }
+
+    public static String enterprisePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<enterprise>");
+        buffer.append("<cpuHard>0</cpuHard>");
+        buffer.append("<cpuSoft>0</cpuSoft>");
+        buffer.append("<hdHard>0</hdHard>");
+        buffer.append("<hdSoft>0</hdSoft>");
+        buffer.append("<publicIpsHard>0</publicIpsHard>");
+        buffer.append("<publicIpsSoft>0</publicIpsSoft>");
+        buffer.append("<ramHard>0</ramHard>");
+        buffer.append("<ramSoft>0</ramSoft>");
+        buffer.append("<storageHard>0</storageHard>");
+        buffer.append("<storageSoft>0</storageSoft>");
+        buffer.append("<vlansHard>0</vlansHard>");
+        buffer.append("<vlansSoft>0</vlansSoft>");
+        buffer.append("<isReservationRestricted>false</isReservationRestricted>");
+        buffer.append("<name>Kalakaua</name>");
+        buffer.append("<repositoryHard>0</repositoryHard>");
+        buffer.append("<repositorySoft>0</repositorySoft>");
+        buffer.append("</enterprise>");
+        return buffer.toString();
+    }
+
+    public static String enterprisePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<enterprise>");
+        buffer.append(link("/admin/enterprises/1", "edit"));
+        buffer.append(link("/admin/enterprises/1/limits", "limits"));
+        buffer.append(link("/admin/enterprises/1/users", "users"));
+        buffer.append(link("/admin/enterprises/1/properties", "properties"));
+        buffer.append(link("/admin/enterprises/1/reservedmachines", "reservedmachines"));
+        buffer
+            .append(link("/admin/enterprises/1/datacenterrepositories", "datacenterrepositories"));
+        buffer.append(link("/admin/enterprises/1/action/externalnetworks", "externalnetworks"));
+        buffer.append(link("/admin/enterprises/1/action/virtualmachines", "virtualmachines"));
+        buffer.append(link("/admin/enterprises/1/action/virtualdatacenters",
+            "cloud/virtualdatacenters"));
+        buffer.append(link("/admin/enterprises/1/action/virtualappliances", "virtualappliances"));
+        buffer.append(link("/admin/enterprises/1/appslib/templateDefinitionLists",
+            "appslib/templateDefinitionLists"));
+        buffer.append("<cpuHard>0</cpuHard>");
+        buffer.append("<cpuSoft>0</cpuSoft>");
+        buffer.append("<hdHard>0</hdHard>");
+        buffer.append("<hdSoft>0</hdSoft>");
+        buffer.append("<publicIpsHard>0</publicIpsHard>");
+        buffer.append("<publicIpsSoft>0</publicIpsSoft>");
+        buffer.append("<ramHard>0</ramHard>");
+        buffer.append("<ramSoft>0</ramSoft>");
+        buffer.append("<storageHard>0</storageHard>");
+        buffer.append("<storageSoft>0</storageSoft>");
+        buffer.append("<vlansHard>0</vlansHard>");
+        buffer.append("<vlansSoft>0</vlansSoft>");
+        buffer.append("<id>1</id>");
+        buffer.append("<isReservationRestricted>false</isReservationRestricted>");
+        buffer.append("<name>Kalakaua</name>");
+        buffer.append("<repositoryHard>0</repositoryHard>");
+        buffer.append("<repositorySoft>0</repositorySoft>");
+        buffer.append("</enterprise>");
+        return buffer.toString();
+    }
+
+    public static String enterprisePropertiesPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<enterpriseProperties>");
+        buffer.append(link("/admin/enterprises/1/properties", "edit"));
+        buffer.append(link("/admin/enterprises/1", "enterprise"));
+        buffer.append("<id>1</id>");
+        buffer.append("<properties>");
+        buffer.append("<entry>");
+        buffer.append("<key>key</key>");
+        buffer.append("<value>value</value>");
+        buffer.append("</entry>");
+        buffer.append("</properties>");
+        buffer.append("</enterpriseProperties>");
+        return buffer.toString();
+    }
+
+    public static DatacenterLimitsDto datacenterLimitsPost()
+    {
+        DatacenterLimitsDto limits = new DatacenterLimitsDto();
+        limits.setCpuCountLimits(0, 0);
+        limits.setHdLimitsInMb(0, 0);
+        limits.setPublicIPLimits(0, 0);
+        limits.setRamLimitsInMb(0, 0);
+        limits.setStorageLimits(0, 0);
+        limits.setVlansLimits(0, 0);
+        limits.setRepositoryHardLimitsInMb(0);
+        limits.setRepositorySoftLimitsInMb(0);
+        return limits;
+    }
+
+    public static DatacenterLimitsDto datacenterLimitsPut(final EnterpriseDto enterprise)
+    {
+        DatacenterLimitsDto limits = datacenterLimitsPost();
+        limits.setId(1);
+        limits.addLink(new RESTLink("edit", "http://localhost/api/admin/enterprises/"
+            + enterprise.getId() + "/limits/1"));
+        return limits;
+    }
+
+    public static TemplateDefinitionListDto templateListPost()
+    {
+        TemplateDefinitionListDto templateList = new TemplateDefinitionListDto();
+        templateList.setName("myList");
+        templateList.setUrl("http://virtualapp-repository.com/vapp1.ovf");
+        return templateList;
+    }
+
+    public static TemplateDefinitionListDto templateListPut()
+    {
+        TemplateDefinitionListDto templateList = templateListPost();
+        templateList.setId(1);
+        templateList.addLink(new RESTLink("edit",
+            "http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists/1"));
+        templateList
+            .addLink(new RESTLink("repositoryStatus",
+                "http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists/1/actions/repositoryStatus"));
+        return templateList;
+    }
+
+    public static String datacenterLimitsPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<limit>");
+        buffer.append("<cpuHard>0</cpuHard>");
+        buffer.append("<cpuSoft>0</cpuSoft>");
+        buffer.append("<hdHard>0</hdHard>");
+        buffer.append("<hdSoft>0</hdSoft>");
+        buffer.append("<publicIpsHard>0</publicIpsHard>");
+        buffer.append("<publicIpsSoft>0</publicIpsSoft>");
+        buffer.append("<ramHard>0</ramHard>");
+        buffer.append("<ramSoft>0</ramSoft>");
+        buffer.append("<storageHard>0</storageHard>");
+        buffer.append("<storageSoft>0</storageSoft>");
+        buffer.append("<vlansHard>0</vlansHard>");
+        buffer.append("<vlansSoft>0</vlansSoft>");
+        buffer.append("<repositoryHard>0</repositoryHard>");
+        buffer.append("<repositorySoft>0</repositorySoft>");
+        buffer.append("</limit>");
+        return buffer.toString();
+    }
+
+    public static String templateListPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<templateDefinitionList>");
+        buffer.append("<name>myList</name>");
+        buffer.append("<url>http://virtualapp-repository.com/vapp1.ovf</url>");
+        buffer.append("</templateDefinitionList>");
+        return buffer.toString();
+    }
+
+    public static String templateListPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<templateDefinitionList>");
+        buffer.append(link("/admin/enterprises/1/appslib/templateDefinitionLists/1", "edit"));
+        buffer.append(link(
+            "/admin/enterprises/1/appslib/templateDefinitionLists/1/actions/repositoryStatus",
+            "repositoryStatus"));
+        buffer.append("<id>1</id>");
+        buffer.append("<name>myList</name>");
+        buffer.append("<url>http://virtualapp-repository.com/vapp1.ovf</url>");
+        buffer.append("</templateDefinitionList>");
+        return buffer.toString();
+    }
+
+    public static String datacenterLimitsPutPayload(final EnterpriseDto enterprise)
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<limit>");
+        buffer.append(link("/admin/enterprises/" + enterprise.getId() + "/limits/1", "edit"));
+        buffer.append("<cpuHard>0</cpuHard>");
+        buffer.append("<cpuSoft>0</cpuSoft>");
+        buffer.append("<hdHard>0</hdHard>");
+        buffer.append("<hdSoft>0</hdSoft>");
+        buffer.append("<publicIpsHard>0</publicIpsHard>");
+        buffer.append("<publicIpsSoft>0</publicIpsSoft>");
+        buffer.append("<ramHard>0</ramHard>");
+        buffer.append("<ramSoft>0</ramSoft>");
+        buffer.append("<storageHard>0</storageHard>");
+        buffer.append("<storageSoft>0</storageSoft>");
+        buffer.append("<vlansHard>0</vlansHard>");
+        buffer.append("<vlansSoft>0</vlansSoft>");
+        buffer.append("<id>1</id>");
+        buffer.append("<repositoryHard>0</repositoryHard>");
+        buffer.append("<repositorySoft>0</repositorySoft>");
+        buffer.append("</limit>");
+        return buffer.toString();
+    }
+
+    public static String userPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<user>");
+        buffer.append(link("/admin/roles/1", "role"));
+        buffer.append("<active>true</active>");
+        buffer.append("<authType>ABIQUO</authType>");
+        buffer.append("<description>A hawaian user</description>");
+        buffer.append("<email>abe.joha@aloha.com</email>");
+        buffer.append("<locale>en_US</locale>");
+        buffer.append("<name>Aberahama</name>");
+        buffer.append("<nick>abejo</nick>");
+        buffer.append("<password>c69a39bd64ffb77ea7ee3369dce742f3</password>");
+        buffer.append("<surname>Johanson</surname>");
+        buffer.append("</user>");
+        return buffer.toString();
+    }
+
+    public static UserDto userPost()
+    {
+        UserDto user = new UserDto();
+        user.setName("Aberahama");
+        user.setSurname("Johanson");
+        user.setDescription("A hawaian user");
+        user.setEmail("abe.joha@aloha.com");
+        user.setNick("abejo");
+        user.setAuthType("ABIQUO");
+        user.setLocale("en_US");
+        user.setActive(true);
+        user.setPassword("c69a39bd64ffb77ea7ee3369dce742f3");
+        user.addLink(new RESTLink("role", "http://localhost/api/admin/roles/1"));
+        return user;
+    }
+
+    public static String userPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<user>");
+        buffer.append(link("/admin/roles/1", "role"));
+        buffer.append(link("/admin/enterprises/1/users/1", "edit"));
+        buffer.append(link("/admin/enterprises/1", "enterprise"));
+        buffer
+            .append(link("/admin/enterprises/1/users/1/action/virtualmachines", "virtualmachines"));
+        buffer.append("<active>true</active>");
+        buffer.append("<authType>ABIQUO</authType>");
+        buffer.append("<description>A hawaian user</description>");
+        buffer.append("<email>abe.joha@aloha.com</email>");
+        buffer.append("<id>1</id>");
+        buffer.append("<locale>en_US</locale>");
+        buffer.append("<name>Aberahama</name>");
+        buffer.append("<nick>abejo</nick>");
+        buffer.append("<password>c69a39bd64ffb77ea7ee3369dce742f3</password>");
+        buffer.append("<surname>Johanson</surname>");
+        buffer.append("</user>");
+        return buffer.toString();
+    }
+
+    public static UserDto userPut()
+    {
+        UserDto user = userPost();
+        user.setId(1);
+        user.addLink(new RESTLink("edit", "http://localhost/api/admin/enterprises/1/users/1"));
+        user.addLink(new RESTLink("enterprise", "http://localhost/api/admin/enterprises/1"));
+        user.addLink(new RESTLink("virtualmachines",
+            "http://localhost/api/admin/enterprises/1/users/1/action/virtualmachines"));
+        return user;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/InfrastructureResources.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/InfrastructureResources.java
new file mode 100644
index 0000000..89cef97
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/InfrastructureResources.java
@@ -0,0 +1,555 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.domain.DomainUtils.link;
+
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.OrganizationDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.abiquo.server.core.infrastructure.RemoteServiceDto;
+import com.abiquo.server.core.infrastructure.UcsRackDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+
+/**
+ * Infrastructure domain utilities.
+ * 
+ * @author Ignasi Barrera
+ */
+public class InfrastructureResources
+{
+    public static DatacenterDto datacenterPost()
+    {
+        DatacenterDto datacenter = new DatacenterDto();
+        datacenter.setName("DC");
+        datacenter.setLocation("Honolulu");
+        return datacenter;
+    }
+
+    public static RackDto rackPost()
+    {
+        RackDto rack = new RackDto();
+        rack.setName("Aloha");
+        rack.setShortDescription("A hawaian rack");
+        rack.setHaEnabled(false);
+        rack.setVlanIdMin(6);
+        rack.setVlanIdMax(3024);
+        rack.setVlanPerVdcReserved(6);
+        rack.setNrsq(80);
+        return rack;
+    }
+
+    public static UcsRackDto managedRackPost()
+    {
+        UcsRackDto rack = new UcsRackDto();
+        rack.setName("Aloha");
+        rack.setShortDescription("A hawaian rack");
+        rack.setHaEnabled(false);
+        rack.setVlanIdMin(6);
+        rack.setVlanIdMax(3024);
+        rack.setVlanPerVdcReserved(6);
+        rack.setNrsq(80);
+        return rack;
+    }
+
+    public static MachineDto machinePost()
+    {
+        MachineDto machine = new MachineDto();
+        machine.setName("Kamehameha");
+        machine.setVirtualCpuCores(3);
+        machine.setDescription("A hawaian machine");
+        machine.setVirtualRamInMb(512);
+        machine.setVirtualSwitch("192.168.1.10");
+        return machine;
+    }
+
+    public static RemoteServiceDto remoteServicePost()
+    {
+        RemoteServiceDto remoteService = new RemoteServiceDto();
+        remoteService.setType(RemoteServiceType.NODE_COLLECTOR);
+        remoteService.setUri("http://localhost:80/nodecollector");
+        remoteService.setStatus(0);
+        return remoteService;
+    }
+
+    public static StorageDeviceDto storageDevicePost()
+    {
+        StorageDeviceDto storage = new StorageDeviceDto();
+        storage.setName("Aloha aloha");
+        storage.setIscsiIp("10.10.10.10");
+        storage.setIscsiPort(99);
+        storage.setManagementPort(90);
+
+        return storage;
+    }
+
+    public static StoragePoolDto storagePoolPost()
+    {
+        StoragePoolDto storagePool = new StoragePoolDto();
+        storagePool.setName("Hawaian Storage Pool");
+        return storagePool;
+    }
+
+    public static DatacenterDto datacenterPut()
+    {
+        DatacenterDto datacenter = datacenterPost();
+        datacenter.setId(1);
+        datacenter.addLink(new RESTLink("checkmachinestate",
+            "http://localhost/api/admin/datacenters/1/action/checkmachinestate"));
+        datacenter.addLink(new RESTLink("checkmachineipmistate",
+            "http://localhost/api/admin/datacenters/1/action/checkmachineipmistate"));
+        datacenter.addLink(new RESTLink("checkremoteservice",
+            "http://localhost/api/admin/datacenters/1/action/checkremoteservice"));
+        datacenter.addLink(new RESTLink("devices",
+            "http://localhost/api/admin/datacenters/1/storage/devices"));
+        datacenter.addLink(new RESTLink("discovermultiple",
+            "http://localhost/api/admin/datacenters/1/action/discovermultiple"));
+        datacenter.addLink(new RESTLink("discoversingle",
+            "http://localhost/api/admin/datacenters/1/action/discoversingle"));
+        datacenter.addLink(new RESTLink("edit", "http://localhost/api/admin/datacenters/1"));
+        datacenter.addLink(new RESTLink("getLimits",
+            "http://localhost/api/admin/datacenters/1/action/getLimits"));
+        datacenter.addLink(new RESTLink("racks", "http://localhost/api/admin/datacenters/1/racks"));
+        datacenter.addLink(new RESTLink("remoteservices",
+            "http://localhost/api/admin/datacenters/1/remoteservices"));
+        datacenter.addLink(new RESTLink("tiers",
+            "http://localhost/api/admin/datacenters/1/storage/tiers"));
+        datacenter.addLink(new RESTLink("network",
+            "http://localhost/api/admin/datacenters/1/network"));
+        datacenter.addLink(new RESTLink("enterprises",
+            "http://localhost/api/admin/datacenters/1/action/enterprises"));
+        datacenter.addLink(new RESTLink("hypervisor",
+            "http://localhost/api/admin/datacenters/1/action/hypervisor"));
+        datacenter.addLink(new RESTLink("hypervisors",
+            "http://localhost/api/admin/datacenters/1/hypervisors"));
+        return datacenter;
+    }
+
+    public static RackDto rackPut()
+    {
+        RackDto rack = rackPost();
+        rack.setId(1);
+        rack.addLink(new RESTLink("datacenter", "http://localhost/api/admin/datacenters/1"));
+        rack.addLink(new RESTLink("edit", "http://localhost/api/admin/datacenters/1/racks/1"));
+        rack.addLink(new RESTLink("machines",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines"));
+        return rack;
+    }
+
+    public static UcsRackDto managedRackPut()
+    {
+        UcsRackDto rack = managedRackPost();
+        rack.setId(1);
+        rack.addLink(new RESTLink("datacenter", "http://localhost/api/admin/datacenters/1"));
+        rack.addLink(new RESTLink("edit", "http://localhost/api/admin/datacenters/1/racks/1"));
+        rack.addLink(new RESTLink("fsm", "http://localhost/api/admin/datacenters/1/racks/1/fsm"));
+        rack.addLink(new RESTLink("logicservers",
+            "http://localhost/api/admin/datacenters/1/racks/1/logicservers"));
+        rack.addLink(new RESTLink("ls-templates",
+            "http://localhost/api/admin/datacenters/1/racks/1/lstemplates"));
+        rack.addLink(new RESTLink("organizations",
+            "http://localhost/api/admin/datacenters/1/racks/1/organizations"));
+        rack.addLink(new RESTLink("ls-associate",
+            "http://localhost/api/admin/datacenters/1/racks/1/logicservers/associate"));
+        rack.addLink(new RESTLink("ls-associateclone",
+            "http://localhost/api/admin/datacenters/1/racks/1/logicservers/assocclone"));
+        rack.addLink(new RESTLink("ls-associatetemplate",
+            "http://localhost/api/admin/datacenters/1/racks/1/logicservers/associatetemplate"));
+        rack.addLink(new RESTLink("ls-clone",
+            "http://localhost/api/admin/datacenters/1/racks/1/logicservers/clone"));
+        rack.addLink(new RESTLink("ls-delete",
+            "http://localhost/api/admin/datacenters/1/racks/1/logicservers/delete"));
+        rack.addLink(new RESTLink("ls-dissociate",
+            "http://localhost/api/admin/datacenters/1/racks/1/logicservers/dissociate"));
+        return rack;
+    }
+
+    public static LogicServerDto logicServerPut()
+    {
+        LogicServerDto logicServer = new LogicServerDto();
+        logicServer.setName("server");
+        logicServer.setAssociated("associated");
+        logicServer.setType("instance");
+
+        return logicServer;
+    }
+
+    public static OrganizationDto organizationPut()
+    {
+        OrganizationDto org = new OrganizationDto();
+        org.setName("org");
+        org.setDn("org-root/org-Finance");
+        org.setLevel("1");
+
+        return org;
+    }
+
+    public static TierDto tierPut()
+    {
+        TierDto tier = new TierDto();
+        tier.setId(1);
+        tier.setEnabled(true);
+        tier.setName("Tier");
+        tier.addLink(new RESTLink("edit",
+            "http://localhost/api/admin/datacenters/1/storage/tiers/1"));
+        tier.addLink(new RESTLink("datacenter", "http://localhost/api/admin/datacenters/1"));
+        tier.addLink(new RESTLink("pools",
+            "http://localhost/api/admin/datacenters/1/storage/tiers/1/pools"));
+
+        return tier;
+    }
+
+    public static StorageDeviceDto storageDevicePut()
+    {
+        StorageDeviceDto storageDevice = storageDevicePost();
+        storageDevice.setId(1);
+        storageDevice
+            .addLink(new RESTLink("datacenter", "http://localhost/api/admin/datacenters/1"));
+        storageDevice.addLink(new RESTLink("edit",
+            "http://localhost/api/admin/datacenters/1/storage/devices/1"));
+        storageDevice.addLink(new RESTLink("pools",
+            "http://localhost/api/admin/datacenters/1/storage/devices/1/pools"));
+
+        return storageDevice;
+    }
+
+    public static StoragePoolDto storagePoolPut()
+    {
+        StoragePoolDto storagePool = storagePoolPost();
+        storagePool.setIdStorage("tururututu");
+        storagePool.addLink(new RESTLink("device",
+            "http://localhost/api/admin/datacenters/1/storage/devices/1"));
+        storagePool.addLink(new RESTLink("edit",
+            "http://localhost/api/admin/datacenters/1/storage/devices/1/pools/tururututu"));
+
+        return storagePool;
+    }
+
+    public static RemoteServiceDto remoteServicePut()
+    {
+        RemoteServiceDto remoteService = remoteServicePost();
+        remoteService.setId(1);
+        remoteService.addLink(new RESTLink("check",
+            "http://localhost/api/admin/datacenters/1/remoteservices/nodecollector/action/check"));
+        remoteService
+            .addLink(new RESTLink("datacenter", "http://localhost/api/admin/datacenters/1"));
+        remoteService.addLink(new RESTLink("edit",
+            "http://localhost/api/admin/datacenters/1/remoteservices/nodecollector"));
+        return remoteService;
+    }
+
+    public static MachineDto machinePut()
+    {
+        MachineDto machine = machinePost();
+        machine.setId(1);
+        machine.addLink(new RESTLink("edit",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1"));
+        machine.addLink(new RESTLink("rack", "http://localhost/api/admin/datacenters/1/racks/1"));
+        machine.addLink(new RESTLink("checkstate",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/checkstate"));
+        machine.addLink(new RESTLink("checkipmistate",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/checkipmistate"));
+        machine.addLink(new RESTLink("led",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/led"));
+        machine.addLink(new RESTLink("ledoff",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/ledoff"));
+        machine.addLink(new RESTLink("ledon",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/ledon"));
+        machine.addLink(new RESTLink("logicserver",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/logicserver"));
+        machine.addLink(new RESTLink("poweroff",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/poweroff"));
+        machine.addLink(new RESTLink("poweron",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/poweron"));
+        machine.addLink(new RESTLink("virtualmachines",
+            "http://localhost/api/admin/datacenters/1/racks/1/machines/1/virtualmachines"));
+        machine.setVirtualCpuCores(5);
+
+        return machine;
+    }
+
+    public static String datacenterPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<datacenter>");
+        buffer.append("<location>Honolulu</location>");
+        buffer.append("<name>DC</name>");
+        buffer.append("</datacenter>");
+        return buffer.toString();
+    }
+
+    public static String rackPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<rack>");
+        buffer.append("<haEnabled>false</haEnabled>");
+        buffer.append("<name>Aloha</name>");
+        buffer.append("<nrsq>80</nrsq>");
+        buffer.append("<shortDescription>A hawaian rack</shortDescription>");
+        buffer.append("<vlanIdMax>3024</vlanIdMax>");
+        buffer.append("<vlanIdMin>6</vlanIdMin>");
+        buffer.append("<vlanPerVdcReserved>6</vlanPerVdcReserved>");
+        buffer.append("</rack>");
+        return buffer.toString();
+    }
+
+    public static String managedRackPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<ucsrack>");
+        buffer.append("<haEnabled>false</haEnabled>");
+        buffer.append("<name>Aloha</name>");
+        buffer.append("<nrsq>80</nrsq>");
+        buffer.append("<shortDescription>A hawaian rack</shortDescription>");
+        buffer.append("<vlanIdMax>3024</vlanIdMax>");
+        buffer.append("<vlanIdMin>6</vlanIdMin>");
+        buffer.append("<vlanPerVdcReserved>6</vlanPerVdcReserved>");
+        buffer.append("</ucsrack>");
+        return buffer.toString();
+    }
+
+    public static String storagePoolPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<storagePool>");
+        buffer.append("<availableSizeInMb>0</availableSizeInMb>");
+        buffer.append("<enabled>false</enabled>");
+        buffer.append("<name>Hawaian Storage Pool</name>");
+        buffer.append("<totalSizeInMb>0</totalSizeInMb>");
+        buffer.append("<usedSizeInMb>0</usedSizeInMb>");
+        buffer.append("</storagePool>");
+        return buffer.toString();
+    }
+
+    public static String storageDevicePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<device>");
+        buffer.append("<iscsiIp>10.10.10.10</iscsiIp>");
+        buffer.append("<iscsiPort>99</iscsiPort>");
+        buffer.append("<managementPort>90</managementPort>");
+        buffer.append("<name>Aloha aloha</name>");
+        buffer.append("</device>");
+        return buffer.toString();
+    }
+
+    public static String machinePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<machine>");
+        buffer.append("<datastores/>");
+        buffer.append("<description>A hawaian machine</description>");
+        buffer.append("<name>Kamehameha</name>");
+        buffer.append("<cpu>3</cpu>");
+        buffer.append("<cpuUsed>1</cpuUsed>");
+        buffer.append("<ram>512</ram>");
+        buffer.append("<ramUsed>1</ramUsed>");
+        buffer.append("<virtualSwitch>192.168.1.10</virtualSwitch>");
+        buffer.append("</machine>");
+        return buffer.toString();
+    }
+
+    public static String remoteServicePostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<remoteService>");
+        buffer.append("<status>0</status>");
+        buffer.append("<type>NODE_COLLECTOR</type>");
+        buffer.append("<uri>http://localhost:80/nodecollector</uri>");
+        buffer.append("</remoteService>");
+        return buffer.toString();
+    }
+
+    public static String datacenterPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<datacenter>");
+        buffer.append(link("/admin/datacenters/1/action/checkmachinestate", "checkmachinestate"));
+        buffer.append(link("/admin/datacenters/1/action/checkmachineipmistate",
+            "checkmachineipmistate"));
+        buffer.append(link("/admin/datacenters/1/action/checkremoteservice", "checkremoteservice"));
+        buffer.append(link("/admin/datacenters/1/storage/devices", "devices"));
+        buffer.append(link("/admin/datacenters/1/action/discovermultiple", "discovermultiple"));
+        buffer.append(link("/admin/datacenters/1/action/discoversingle", "discoversingle"));
+        buffer.append(link("/admin/datacenters/1", "edit"));
+        buffer.append(link("/admin/datacenters/1/action/getLimits", "getLimits"));
+        buffer.append(link("/admin/datacenters/1/racks", "racks"));
+        buffer.append(link("/admin/datacenters/1/remoteservices", "remoteservices"));
+        buffer.append(link("/admin/datacenters/1/storage/tiers", "tiers"));
+        buffer.append(link("/admin/datacenters/1/network", "network"));
+        buffer.append(link("/admin/datacenters/1/action/enterprises", "enterprises"));
+        buffer.append(link("/admin/datacenters/1/action/hypervisor", "hypervisor"));
+        buffer.append(link("/admin/datacenters/1/hypervisors", "hypervisors"));
+        buffer.append("<id>1</id>");
+        buffer.append("<location>Honolulu</location>");
+        buffer.append("<name>DC</name>");
+        buffer.append("</datacenter>");
+        return buffer.toString();
+    }
+
+    public static String storagePoolPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<storagePool>");
+        buffer.append(link("/admin/datacenters/1/storage/devices/1", "device"));
+        buffer.append(link("/admin/datacenters/1/storage/devices/1/pools/tururututu", "edit"));
+        buffer.append("<availableSizeInMb>0</availableSizeInMb>");
+        buffer.append("<enabled>false</enabled>");
+        buffer.append("<idStorage>tururututu</idStorage>");
+        buffer.append("<name>Hawaian Storage Pool</name>");
+        buffer.append("<totalSizeInMb>0</totalSizeInMb>");
+        buffer.append("<usedSizeInMb>0</usedSizeInMb>");
+        buffer.append("</storagePool>");
+        return buffer.toString();
+    }
+
+    public static String tierPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<tier>");
+        buffer.append(link("/admin/datacenters/1/storage/tiers/1", "edit"));
+        buffer.append(link("/admin/datacenters/1", "datacenter"));
+        buffer.append(link("/admin/datacenters/1/storage/tiers/1/pools", "pools"));
+        buffer.append("<enabled>true</enabled>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>Tier</name>");
+        buffer.append("</tier>");
+        return buffer.toString();
+    }
+
+    public static String rackPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<rack>");
+        buffer.append(link("/admin/datacenters/1", "datacenter"));
+        buffer.append(link("/admin/datacenters/1/racks/1", "edit"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines", "machines"));
+        buffer.append("<haEnabled>false</haEnabled>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>Aloha</name>");
+        buffer.append("<nrsq>80</nrsq>");
+        buffer.append("<shortDescription>A hawaian rack</shortDescription>");
+        buffer.append("<vlanIdMax>3024</vlanIdMax>");
+        buffer.append("<vlanIdMin>6</vlanIdMin>");
+        buffer.append("<vlanPerVdcReserved>6</vlanPerVdcReserved>");
+        buffer.append("</rack>");
+        return buffer.toString();
+    }
+
+    public static String managedRackPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<ucsrack>");
+        buffer.append(link("/admin/datacenters/1", "datacenter"));
+        buffer.append(link("/admin/datacenters/1/racks/1", "edit"));
+        buffer.append(link("/admin/datacenters/1/racks/1/fsm", "fsm"));
+        buffer.append(link("/admin/datacenters/1/racks/1/logicservers", "logicservers"));
+        buffer.append(link("/admin/datacenters/1/racks/1/lstemplates", "ls-templates"));
+        buffer.append(link("/admin/datacenters/1/racks/1/organizations", "organizations"));
+        buffer.append(link("/admin/datacenters/1/racks/1/logicservers/associate", "ls-associate"));
+        buffer.append(link("/admin/datacenters/1/racks/1/logicservers/assocclone",
+            "ls-associateclone"));
+        buffer.append(link("/admin/datacenters/1/racks/1/logicservers/associatetemplate",
+            "ls-associatetemplate"));
+        buffer.append(link("/admin/datacenters/1/racks/1/logicservers/clone", "ls-clone"));
+        buffer.append(link("/admin/datacenters/1/racks/1/logicservers/delete", "ls-delete"));
+        buffer
+            .append(link("/admin/datacenters/1/racks/1/logicservers/dissociate", "ls-dissociate"));
+        buffer.append("<haEnabled>false</haEnabled>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>Aloha</name>");
+        buffer.append("<nrsq>80</nrsq>");
+        buffer.append("<shortDescription>A hawaian rack</shortDescription>");
+        buffer.append("<vlanIdMax>3024</vlanIdMax>");
+        buffer.append("<vlanIdMin>6</vlanIdMin>");
+        buffer.append("<vlanPerVdcReserved>6</vlanPerVdcReserved>");
+        buffer.append("</ucsrack>");
+        return buffer.toString();
+    }
+
+    public static String storageDevicePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<device>");
+        buffer.append(link("/admin/datacenters/1", "datacenter"));
+        buffer.append(link("/admin/datacenters/1/storage/devices/1", "edit"));
+        buffer.append(link("/admin/datacenters/1/storage/devices/1/pools", "pools"));
+        buffer.append("<id>1</id>");
+        buffer.append("<iscsiIp>10.10.10.10</iscsiIp>");
+        buffer.append("<iscsiPort>99</iscsiPort>");
+        buffer.append("<managementPort>90</managementPort>");
+        buffer.append("<name>Aloha aloha</name>");
+        buffer.append("</device>");
+        return buffer.toString();
+    }
+
+    public static String remoteServicePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<remoteService>");
+        buffer.append(link("/admin/datacenters/1/remoteservices/nodecollector/action/check",
+            "check"));
+        buffer.append(link("/admin/datacenters/1", "datacenter"));
+        buffer.append(link("/admin/datacenters/1/remoteservices/nodecollector", "edit"));
+        buffer.append("<id>1</id>");
+        buffer.append("<status>0</status>");
+        buffer.append("<type>NODE_COLLECTOR</type>");
+        buffer.append("<uri>http://localhost:80/nodecollector</uri>");
+        buffer.append("</remoteService>");
+        return buffer.toString();
+    }
+
+    public static String machinePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<machine>");
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1", "edit"));
+        buffer.append(link("/admin/datacenters/1/racks/1", "rack"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/action/checkstate",
+            "checkstate"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/action/checkipmistate",
+            "checkipmistate"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/led", "led"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/action/ledoff", "ledoff"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/action/ledon", "ledon"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/logicserver", "logicserver"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/action/poweroff", "poweroff"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/action/poweron", "poweron"));
+        buffer.append(link("/admin/datacenters/1/racks/1/machines/1/virtualmachines",
+            "virtualmachines"));
+        buffer.append("<datastores/>");
+        buffer.append("<description>A hawaian machine</description>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>Kamehameha</name>");
+        buffer.append("<cpu>5</cpu>");
+        buffer.append("<cpuUsed>1</cpuUsed>");
+        buffer.append("<ram>512</ram>");
+        buffer.append("<ramUsed>1</ramUsed>");
+        buffer.append("<virtualSwitch>192.168.1.10</virtualSwitch>");
+        buffer.append("</machine>");
+        return buffer.toString();
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/NetworkResources.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/NetworkResources.java
new file mode 100644
index 0000000..6db98f4
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/NetworkResources.java
@@ -0,0 +1,277 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.domain.DomainUtils.link;
+
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.infrastructure.network.NicDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+
+/**
+ * Network domain utilities.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class NetworkResources
+{
+    public static VLANNetworkDto vlanPost()
+    {
+        VLANNetworkDto vlan = new VLANNetworkDto();
+        vlan.setAddress("192.168.1.0");
+        vlan.setDefaultNetwork(true);
+        vlan.setName("DefaultNetwork");
+        vlan.setGateway("192.168.1.1");
+        vlan.setMask(24);
+
+        return vlan;
+    }
+
+    public static PrivateIpDto privateIpPut()
+    {
+        PrivateIpDto ip = new PrivateIpDto();
+        ip.setId(1);
+        ip.setName("private ip");
+        ip.setMac("00:58:5A:c0:C3:01");
+        RESTLink self =
+            new RESTLink("self",
+                "http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1/ips/1");
+        self.setTitle("privateip");
+        ip.addLink(self);
+        return ip;
+    }
+
+    public static PublicIpDto publicIpToPurchase()
+    {
+        PublicIpDto ip = new PublicIpDto();
+        RESTLink self =
+            new RESTLink("purchase",
+                "http://localhost/api/cloud/virtualdatacenters/5/publicips/purchased/1");
+        ip.addLink(self);
+        return ip;
+    }
+
+    public static PublicIpDto publicIpToRelease()
+    {
+        PublicIpDto ip = new PublicIpDto();
+        RESTLink self =
+            new RESTLink("release",
+                "http://localhost/api/cloud/virtualdatacenters/5/publicips/topurchase/1");
+        ip.addLink(self);
+        return ip;
+    }
+
+    public static NicDto nicPut()
+    {
+        NicDto nic = new NicDto();
+        nic.setId(1);
+        nic.setIp("123.123.123.123");
+        nic.setMac("00:58:5A:c0:C3:01");
+        nic.addLink(new RESTLink("edit",
+            "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/network/nics/1"));
+
+        return nic;
+    }
+
+    public static VLANNetworkDto privateNetworkPut()
+    {
+        VLANNetworkDto vlan = new VLANNetworkDto();
+        vlan.setId(1);
+        vlan.setAddress("192.168.1.0");
+        vlan.setDefaultNetwork(true);
+        vlan.setName("DefaultNetwork");
+        vlan.setGateway("192.168.1.1");
+        vlan.setMask(24);
+        vlan.setType(NetworkType.INTERNAL);
+        vlan.addLink(new RESTLink("edit",
+            "http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1"));
+        vlan.addLink(new RESTLink("ips",
+            "http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1/ips"));
+
+        return vlan;
+    }
+
+    public static VLANNetworkDto publicNetworkPut()
+    {
+        VLANNetworkDto vlan = new VLANNetworkDto();
+        vlan.setId(1);
+        vlan.setAddress("192.168.1.0");
+        vlan.setDefaultNetwork(true);
+        vlan.setName("PublicNetwork");
+        vlan.setGateway("192.168.1.1");
+        vlan.setMask(24);
+        vlan.setType(NetworkType.PUBLIC);
+        vlan.addLink(new RESTLink("edit", "http://localhost/api/admin/datacenters/1/network/1"));
+        vlan.addLink(new RESTLink("ips", "http://localhost/api/admin/datacenters/1/network/1/ips"));
+
+        return vlan;
+    }
+
+    public static VLANNetworkDto externalNetworkPut()
+    {
+        VLANNetworkDto vlan = new VLANNetworkDto();
+        vlan.setId(1);
+        vlan.setAddress("192.168.1.0");
+        vlan.setDefaultNetwork(true);
+        vlan.setName("ExternalNetwork");
+        vlan.setGateway("192.168.1.1");
+        vlan.setMask(24);
+        vlan.setType(NetworkType.EXTERNAL);
+        vlan.addLink(new RESTLink("edit", "http://localhost/api/admin/datacenters/1/network/1"));
+        vlan.addLink(new RESTLink("enterprise", "http://localhost/api/admin/enterprises/1"));
+        vlan.addLink(new RESTLink("ips",
+            "http://localhost/api/admin/enterprises/1/limits/1/externalnetworks/1/ips"));
+
+        return vlan;
+    }
+
+    public static VLANNetworkDto unmanagedNetworkPut()
+    {
+        VLANNetworkDto vlan = new VLANNetworkDto();
+        vlan.setId(1);
+        vlan.setAddress("192.168.1.0");
+        vlan.setDefaultNetwork(true);
+        vlan.setName("UnmanagedNetwork");
+        vlan.setGateway("192.168.1.1");
+        vlan.setMask(24);
+        vlan.setType(NetworkType.UNMANAGED);
+        vlan.addLink(new RESTLink("edit", "http://localhost/api/admin/datacenters/1/network/1"));
+        vlan.addLink(new RESTLink("enterprise", "http://localhost/api/admin/enterprises/1"));
+        vlan.addLink(new RESTLink("ips",
+            "http://localhost/api/admin/enterprises/1/limits/1/externalnetworks/1/ips"));
+
+        return vlan;
+    }
+
+    public static String vlanNetworkPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<network>");
+        buffer.append("<address>192.168.1.0</address>");
+        buffer.append("<defaultNetwork>true</defaultNetwork>");
+        buffer.append("<gateway>192.168.1.1</gateway>");
+        buffer.append("<mask>24</mask>");
+        buffer.append("<name>DefaultNetwork</name>");
+        buffer.append("</network>");
+        return buffer.toString();
+    }
+
+    public static String privateNetworkPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<network>");
+        buffer.append(link("/cloud/virtualdatacenters/1/privatenetworks/1", "edit"));
+        buffer.append(link("/cloud/virtualdatacenters/1/privatenetworks/1/ips", "ips"));
+        buffer.append("<address>192.168.1.0</address>");
+        buffer.append("<defaultNetwork>true</defaultNetwork>");
+        buffer.append("<gateway>192.168.1.1</gateway>");
+        buffer.append("<id>1</id>");
+        buffer.append("<mask>24</mask>");
+        buffer.append("<name>DefaultNetwork</name>");
+        buffer.append("<type>INTERNAL</type>");
+        buffer.append("</network>");
+        return buffer.toString();
+    }
+
+    public static String publicNetworkPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<network>");
+        buffer.append(link("/admin/datacenters/1/network/1", "edit"));
+        buffer.append(link("/admin/datacenters/1/network/1/ips", "ips"));
+        buffer.append("<address>192.168.1.0</address>");
+        buffer.append("<defaultNetwork>true</defaultNetwork>");
+        buffer.append("<gateway>192.168.1.1</gateway>");
+        buffer.append("<id>1</id>");
+        buffer.append("<mask>24</mask>");
+        buffer.append("<name>PublicNetwork</name>");
+        buffer.append("<type>PUBLIC</type>");
+        buffer.append("</network>");
+        return buffer.toString();
+    }
+
+    public static String externalNetworkPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<network>");
+        buffer.append(link("/admin/datacenters/1/network/1", "edit"));
+        buffer.append(link("/admin/enterprises/1", "enterprise"));
+        buffer.append(link("/admin/enterprises/1/limits/1/externalnetworks/1/ips", "ips"));
+        buffer.append("<address>192.168.1.0</address>");
+        buffer.append("<defaultNetwork>true</defaultNetwork>");
+        buffer.append("<gateway>192.168.1.1</gateway>");
+        buffer.append("<id>1</id>");
+        buffer.append("<mask>24</mask>");
+        buffer.append("<name>ExternalNetwork</name>");
+        buffer.append("<type>EXTERNAL</type>");
+        buffer.append("</network>");
+        return buffer.toString();
+    }
+
+    public static String unmanagedNetworkPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<network>");
+        buffer.append(link("/admin/datacenters/1/network/1", "edit"));
+        buffer.append(link("/admin/enterprises/1", "enterprise"));
+        buffer.append(link("/admin/enterprises/1/limits/1/externalnetworks/1/ips", "ips"));
+        buffer.append("<address>192.168.1.0</address>");
+        buffer.append("<defaultNetwork>true</defaultNetwork>");
+        buffer.append("<gateway>192.168.1.1</gateway>");
+        buffer.append("<id>1</id>");
+        buffer.append("<mask>24</mask>");
+        buffer.append("<name>UnmanagedNetwork</name>");
+        buffer.append("<type>UNMANAGED</type>");
+        buffer.append("</network>");
+        return buffer.toString();
+    }
+
+    public static String privateIpPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<ipPoolManagement>");
+        buffer.append(link("/cloud/virtualdatacenters/1/privatenetworks/1/ips/1", "self",
+            "privateip"));
+        buffer.append("<available>false</available>");
+        buffer.append("<id>1</id>");
+        buffer.append("<mac>00:58:5A:c0:C3:01</mac>");
+        buffer.append("<name>private ip</name>");
+        buffer.append("<quarantine>false</quarantine>");
+        buffer.append("</ipPoolManagement>");
+        return buffer.toString();
+    }
+
+    public static String linksDtoPayload(final LinksDto dto)
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<links>");
+        for (RESTLink link : dto.getLinks())
+        {
+            buffer.append(link(link));
+        }
+        buffer.append("</links>");
+        return buffer.toString();
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/PricingResources.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/PricingResources.java
new file mode 100644
index 0000000..f694aa5
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/PricingResources.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.domain.DomainUtils.link;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.pricing.CurrencyDto;
+
+/**
+ * Enterprise domain utilities.
+ * 
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ */
+public class PricingResources
+{
+
+    public static CurrencyDto currencyPost()
+    {
+        CurrencyDto currency = new CurrencyDto();
+        currency.setName("yuan");
+        currency.setSymbol("¥");
+        currency.setDigits(3);
+        return currency;
+    }
+
+    public static CurrencyDto currencyPut()
+    {
+        CurrencyDto currency = new CurrencyDto();
+        currency.setName("yuan");
+        currency.setSymbol("¥");
+        currency.setDigits(3);
+        currency.setId(1);
+        currency.addLink(new RESTLink("edit", "http://localhost/api/config/currencies/1"));
+        return currency;
+    }
+
+    public static String currencyPostPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<currency>");
+        buffer.append("<symbol>¥</symbol>");
+        buffer.append("<digits>3</digits>");
+        buffer.append("<name>yuan</name>");
+        buffer.append("</currency>");
+        return buffer.toString();
+    }
+
+    public static String currencyPutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<currency>");
+        buffer.append(link("/config/currencies/1", "edit"));
+        buffer.append("<symbol>¥</symbol>");
+        buffer.append("<digits>3</digits>");
+        buffer.append("<id>1</id>");
+        buffer.append("<name>yuan</name>");
+        buffer.append("</currency>");
+        return buffer.toString();
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/TemplateResources.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/TemplateResources.java
new file mode 100644
index 0000000..d8f67b4
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/TemplateResources.java
@@ -0,0 +1,178 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain;
+
+import static org.jclouds.abiquo.domain.DomainUtils.link;
+
+import com.abiquo.model.enumerator.ConversionState;
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.appslibrary.ConversionDto;
+import com.abiquo.server.core.appslibrary.DatacenterRepositoryDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatePersistentDto;
+
+/**
+ * VM template domain utilities.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+public class TemplateResources
+{
+    public static DatacenterRepositoryDto datacenterRepositoryPut()
+    {
+        DatacenterRepositoryDto dcRepository = new DatacenterRepositoryDto();
+        dcRepository.setName("Datacenter Repo");
+        dcRepository.setRepositoryCapacityMb(0);
+        dcRepository.setRepositoryLocation("10.60.1.104:/volume1/nfs-devel");
+        dcRepository.setRepositoryRemainingMb(0);
+        dcRepository.addLink(new RESTLink("applianceManagerRepositoryUri",
+            "http://localhost/am/erepos/1"));
+        dcRepository
+            .addLink(new RESTLink("datacenter", "http://localhost/api/admin/datacenters/1"));
+        dcRepository.addLink(new RESTLink("edit",
+            "http://localhost/api/admin/enterprises/1/datacenterrepositories/1"));
+        dcRepository
+            .addLink(new RESTLink("enterprise", "http://localhost/api/admin/enterprises/1"));
+        dcRepository.addLink(new RESTLink("refresh",
+            "http://localhost/api/admin/enterprises/1/datacenterrepositories/1/actions/refresh"));
+        dcRepository
+            .addLink(new RESTLink("virtualmachinetemplates",
+                "http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates"));
+
+        return dcRepository;
+    }
+
+    public static VirtualMachineTemplateDto virtualMachineTemplatePut()
+    {
+        VirtualMachineTemplateDto template = new VirtualMachineTemplateDto();
+        template.setName("Template");
+        template.setId(1);
+        template.setDescription("Description");
+        template
+            .addLink(new RESTLink("edit",
+                "http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1"));
+        template.addLink(new RESTLink("enterprise", "http://localhost/api/admin/enterprises/1"));
+        template.addLink(new RESTLink("conversions", "http://localhost/api/admin/enterprises/1"
+            + "/datacenterrepositories/1/virtualmachinetemplates/1/conversions"));
+        template.addLink(new RESTLink("tasks", "http://localhost/api/admin/enterprises/1"
+            + "/datacenterrepositories/1/virtualmachinetemplates/1/tasks"));
+
+        return template;
+    }
+
+    public static String virtualMachineTemplatePutPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualMachineTemplate>");
+        buffer.append(link(
+            "/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1", "edit"));
+        buffer.append(link("/admin/enterprises/1", "enterprise"));
+        buffer.append(link("/admin/enterprises/1"
+            + "/datacenterrepositories/1/virtualmachinetemplates/1/conversions", "conversions"));
+
+        buffer.append(link("/admin/enterprises/1"
+            + "/datacenterrepositories/1/virtualmachinetemplates/1/tasks", "tasks"));
+        buffer.append("<id>1</id>");
+        buffer.append("<name>Template</name>");
+        buffer.append("<description>Description</description>");
+        buffer.append("<diskFileSize>0</diskFileSize>");
+        buffer.append("<cpuRequired>0</cpuRequired>");
+        buffer.append("<ramRequired>0</ramRequired>");
+        buffer.append("<hdRequired>0</hdRequired>");
+        buffer.append("<shared>false</shared>");
+        buffer.append("<costCode>0</costCode>");
+        buffer.append("<chefEnabled>false</chefEnabled>");
+        buffer.append("</virtualMachineTemplate>");
+        return buffer.toString();
+    }
+
+    public static VirtualMachineTemplatePersistentDto persistentData()
+    {
+        VirtualMachineTemplatePersistentDto dto = new VirtualMachineTemplatePersistentDto();
+        dto.setPersistentTemplateName("New persistent template name");
+        dto.setPersistentVolumeName("New persistent volume name");
+        dto.addLink(new RESTLink("tier", "http://localhost/api/cloud/virtualdatacenters/1/tiers/1"));
+        dto.addLink(new RESTLink("virtualdatacenter",
+            "http://localhost/api/cloud/virtualdatacenters/1"));
+        dto.addLink(new RESTLink("virtualmachinetemplate",
+            "http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1"));
+        return dto;
+    }
+
+    public static String persistentPayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<virtualmachinetemplatepersistent>");
+        buffer.append(link("/cloud/virtualdatacenters/1/tiers/1", "tier"));
+        buffer.append(link("/cloud/virtualdatacenters/1", "virtualdatacenter"));
+        buffer.append(link(
+            "/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1",
+            "virtualmachinetemplate"));
+        buffer
+            .append("<persistentTemplateName>New persistent template name</persistentTemplateName>");
+        buffer.append("<persistentVolumeName>New persistent volume name</persistentVolumeName>");
+        buffer.append("</virtualmachinetemplatepersistent>");
+        return buffer.toString();
+    }
+
+    public static ConversionDto conversionPut()
+    {
+        ConversionDto conversion = new ConversionDto();
+        conversion.setState(ConversionState.ENQUEUED);
+        conversion.setSourceFormat(DiskFormatType.VMDK_STREAM_OPTIMIZED);
+        conversion.setSourcePath("source/path.vmkd");
+        conversion.setTargetFormat(DiskFormatType.RAW);
+        conversion.setTargetPath("target/path.raw");
+        conversion.setTargetSizeInBytes(1000000l);
+        conversion
+            .addLink(new RESTLink("edit",
+                "http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/conversions/RAW"));
+        conversion
+            .addLink(new RESTLink("tasks",
+                "http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/conversions/RAW/tasks"));
+
+        return conversion;
+    }
+
+    public static String conversionPutPlayload()
+    {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("<conversion>");
+        buffer
+            .append(link(
+                "/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/conversions/RAW",
+                "edit"));
+        buffer
+            .append(link(
+                "/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/conversions/RAW/tasks",
+                "tasks"));
+
+        buffer.append("<state>ENQUEUED</state>");
+        buffer.append("<sourceFormat>VMDK_STREAM_OPTIMIZED</sourceFormat>");
+        buffer.append("<sourcePath>source/path.vmkd</sourcePath>");
+        buffer.append("<targetFormat>RAW</targetFormat>");
+        buffer.append("<targetPath>target/path.raw</targetPath>");
+        buffer.append("<targetSizeInBytes>1000000</targetSizeInBytes>");
+        buffer.append("</conversion>");
+        return buffer.toString();
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/admin/RoleLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/admin/RoleLiveApiTest.java
new file mode 100644
index 0000000..f096f8d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/admin/RoleLiveApiTest.java
@@ -0,0 +1,112 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.admin;
+
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.DomainWrapper;
+import org.jclouds.abiquo.domain.config.Privilege;
+import org.jclouds.abiquo.domain.enterprise.Role;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.config.PrivilegePredicates;
+import org.jclouds.abiquo.predicates.enterprise.RolePredicates;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.enterprise.PrivilegeDto;
+import com.abiquo.server.core.enterprise.RoleDto;
+
+/**
+ * Live integration tests for the {@link Role} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "RoleLiveApiTest")
+public class RoleLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testUpdate()
+    {
+        Role role =
+            Role.builder(env.context.getApiContext()).name("dummyRoleUpdateRole").blocked(false)
+                .build();
+        role.save();
+
+        role.setName("UPDATED_ROLE");
+        role.update();
+
+        // Recover the updated role
+        RoleDto updated = env.adminApi.getRole(role.getId());
+
+        assertEquals(updated.getName(), "UPDATED_ROLE");
+
+        role.delete();
+    }
+
+    public void testCreateRepeated()
+    {
+        Role repeated = Role.Builder.fromRole(env.role).build();
+
+        try
+        {
+            repeated.save();
+            fail("Should not be able to create roles with the same name");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "ROLE-7");
+        }
+    }
+
+    public void testCreateEnterpriseRole()
+    {
+        Role entRole = Role.Builder.fromRole(env.role).build();
+        entRole.setName(entRole.getName() + "enterprise");
+        entRole.setEnterprise(env.enterprise);
+        entRole.save();
+
+        entRole = env.enterprise.findRole(RolePredicates.name(entRole.getName()));
+
+        assertNotNull(entRole);
+    }
+
+    public void testAddPrivilege()
+    {
+        PrivilegeDto dto = env.configApi.getPrivilege(8);
+        Privilege privilege = DomainWrapper.wrap(env.context.getApiContext(), Privilege.class, dto);
+        List<Privilege> privileges = env.role.listPrivileges();
+        privileges.add(privilege);
+
+        env.role.setPrivileges(privileges);
+
+        env.role.update();
+
+        privilege = env.role.findPrivileges(PrivilegePredicates.name(dto.getName()));
+
+        assertNotNull(privilege);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/HardDiskLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/HardDiskLiveApiTest.java
new file mode 100644
index 0000000..9a372a4
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/HardDiskLiveApiTest.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the {@link HardDisk} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "HardDiskLiveApiTest")
+public class HardDiskLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private HardDisk hardDisk;
+
+    public void createHardDisk()
+    {
+        hardDisk =
+            HardDisk.builder(env.context.getApiContext(), env.virtualDatacenter).sizeInMb(64L)
+                .build();
+        hardDisk.save();
+
+        assertNotNull(hardDisk.getId());
+        assertNotNull(hardDisk.getSequence());
+
+        assertNotNull(env.virtualDatacenter.getHardDisk(hardDisk.getId()));
+    }
+
+    @Test(dependsOnMethods = "createHardDisk")
+    public void deleteHardDisk()
+    {
+        HardDisk hd = env.virtualDatacenter.getHardDisk(hardDisk.getId());
+        assertNotNull(hd);
+
+        Integer id = hd.getId();
+        hardDisk.delete();
+        assertNull(env.virtualDatacenter.getHardDisk(id));
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualApplianceLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualApplianceLiveApiTest.java
new file mode 100644
index 0000000..827c83b
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualApplianceLiveApiTest.java
@@ -0,0 +1,108 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualApplianceState;
+
+/**
+ * Live integration tests for the {@link VirtualAppliance} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "VirtualApplianceLiveApiTest")
+public class VirtualApplianceLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testUpdate()
+    {
+        env.virtualAppliance.setName("Virtual AppAloha updated");
+        env.virtualAppliance.update();
+
+        // Recover the updated virtual appliance
+        VirtualApplianceDto updated =
+            env.cloudApi.getVirtualAppliance(env.virtualDatacenter.unwrap(),
+                env.virtualAppliance.getId());
+
+        assertEquals(updated.getName(), "Virtual AppAloha updated");
+    }
+
+    public void testCreateRepeated()
+    {
+        VirtualAppliance repeated =
+            VirtualAppliance.Builder.fromVirtualAppliance(env.virtualAppliance).build();
+
+        repeated.save();
+
+        List<VirtualApplianceDto> virtualAppliances =
+            env.cloudApi.listVirtualAppliances(env.virtualDatacenter.unwrap()).getCollection();
+
+        assertEquals(virtualAppliances.size(), 2);
+        repeated.delete();
+    }
+
+    public void testGetState()
+    {
+        assertEquals(env.virtualAppliance.getState(), VirtualApplianceState.NOT_DEPLOYED);
+    }
+
+    public void testListVirtualMachinesReturnsAll()
+    {
+        List<VirtualMachine> vms = new ArrayList<VirtualMachine>();
+
+        // Pagination by default is set to 25 items per page, so create a few more to verify that
+        // all are returned when listing
+        int numVms = 30;
+
+        for (int i = 0; i < numVms; i++)
+        {
+            VirtualMachine vm =
+                VirtualMachine.Builder.fromVirtualMachine(env.virtualMachine).build();
+            vm.save();
+            vms.add(vm);
+        }
+
+        try
+        {
+            Iterable<VirtualMachine> all = env.virtualAppliance.listVirtualMachines();
+
+            assertNotNull(all);
+            assertTrue(size(all) >= numVms);
+        }
+        finally
+        {
+            for (VirtualMachine vm : vms)
+            {
+                vm.delete();
+            }
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualDatacenterLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualDatacenterLiveApiTest.java
new file mode 100644
index 0000000..5c50250
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualDatacenterLiveApiTest.java
@@ -0,0 +1,209 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static com.google.common.collect.Iterables.size;
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter.Builder;
+import org.jclouds.abiquo.domain.cloud.options.VirtualDatacenterOptions;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.PrivateNetwork;
+import org.jclouds.abiquo.domain.network.PublicIp;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.cloud.VirtualMachineTemplatePredicates;
+import org.jclouds.abiquo.predicates.network.IpPredicates;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+
+/**
+ * Live integration tests for the {@link VirtualDatacenter} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "VirtualDatacenterLiveApiTest")
+public class VirtualDatacenterLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private VirtualMachineTemplate template;
+
+    public void testUpdate()
+    {
+        env.virtualDatacenter.setName("Aloha updated");
+        env.virtualDatacenter.update();
+
+        // Recover the updated virtual datacenter
+        VirtualDatacenterDto updated =
+            env.cloudApi.getVirtualDatacenter(env.virtualDatacenter.getId());
+
+        assertEquals(updated.getName(), "Aloha updated");
+    }
+
+    public void testCreateRepeated()
+    {
+        PrivateNetwork newnet =
+            PrivateNetwork.builder(env.context.getApiContext()).name("Newnet").gateway("10.0.0.1")
+                .address("10.0.0.0").mask(24).build();
+
+        VirtualDatacenter repeated =
+            Builder.fromVirtualDatacenter(env.virtualDatacenter).network(newnet).build();
+
+        repeated.save();
+
+        List<VirtualDatacenterDto> virtualDatacenters =
+            env.cloudApi.listVirtualDatacenters(VirtualDatacenterOptions.builder().build())
+                .getCollection();
+
+        assertEquals(virtualDatacenters.size(), 2);
+        assertEquals(virtualDatacenters.get(0).getName(), virtualDatacenters.get(1).getName());
+        repeated.delete();
+    }
+
+    public void testCreateFromEnterprise()
+    {
+        Enterprise enterprise =
+            env.enterpriseAdminContext.getAdministrationService().getCurrentUser().getEnterprise();
+        assertNotNull(enterprise);
+
+        List<Datacenter> datacenters = enterprise.listAllowedDatacenters();
+        assertNotNull(datacenters);
+        assertTrue(size(datacenters) > 0);
+
+        Datacenter datacenter = datacenters.get(0);
+
+        List<HypervisorType> hypervisors = datacenter.listAvailableHypervisors();
+        assertNotNull(datacenters);
+        assertTrue(size(datacenters) > 0);
+
+        HypervisorType hypervisor = hypervisors.get(0);
+
+        PrivateNetwork network =
+            PrivateNetwork.builder(env.enterpriseAdminContext.getApiContext())
+                .name("DefaultNetwork").gateway("192.168.1.1").address("192.168.1.0").mask(24)
+                .build();
+
+        VirtualDatacenter virtualDatacenter =
+            VirtualDatacenter
+                .builder(env.enterpriseAdminContext.getApiContext(), datacenters.get(0), enterprise)
+                .name(PREFIX + "Plain Virtual Aloha from ENT").cpuCountLimits(18, 20)
+                .hdLimitsInMb(279172872, 279172872).publicIpsLimits(2, 2).ramLimits(19456, 20480)
+                .storageLimits(289910292, 322122547).vlansLimits(1, 2).hypervisorType(hypervisor)
+                .network(network).build();
+
+        virtualDatacenter.save();
+        assertNotNull(virtualDatacenter.getId());
+
+        virtualDatacenter.delete();
+    }
+
+    public void testCreateFromVirtualDatacenter()
+    {
+        HypervisorType hypervisor = env.virtualDatacenter.getHypervisorType();
+
+        Enterprise enterprise = env.user.getEnterprise();
+        assertNotNull(enterprise);
+
+        Datacenter datacenter = env.virtualDatacenter.getDatacenter();
+        assertNotNull(datacenter);
+
+        PrivateNetwork network =
+            PrivateNetwork.builder(env.plainUserContext.getApiContext()).name("DefaultNetwork")
+                .gateway("192.168.1.1").address("192.168.1.0").mask(24).build();
+
+        VirtualDatacenter virtualDatacenter =
+            VirtualDatacenter.builder(env.context.getApiContext(), datacenter, enterprise)
+                .name(PREFIX + "Plain Virtual Aloha from VDC").cpuCountLimits(18, 20)
+                .hdLimitsInMb(279172872, 279172872).publicIpsLimits(2, 2).ramLimits(19456, 20480)
+                .storageLimits(289910292, 322122547).vlansLimits(1, 2).hypervisorType(hypervisor)
+                .network(network).build();
+
+        virtualDatacenter.save();
+        assertNotNull(virtualDatacenter.getId());
+
+        virtualDatacenter.delete();
+    }
+
+    public void testPurchaseIp()
+    {
+        PublicIp publicIp = env.virtualDatacenter.listAvailablePublicIps().get(0);
+        assertNotNull(publicIp);
+        env.virtualDatacenter.purchasePublicIp(publicIp);
+
+        PublicIp apiIp =
+            env.virtualDatacenter.findPurchasedPublicIp(IpPredicates.<PublicIp> address(publicIp
+                .getIp()));
+        assertNotNull(apiIp);
+
+        env.virtualDatacenter.releaseePublicIp(apiIp);
+        apiIp =
+            env.virtualDatacenter.findPurchasedPublicIp(IpPredicates.<PublicIp> address(publicIp
+                .getIp()));
+        assertNull(apiIp);
+    }
+
+    public void testGetDefaultNetwork()
+    {
+        PrivateNetwork network = env.virtualDatacenter.getDefaultNetwork().toPrivateNetwork();
+
+        assertNotNull(network);
+        assertEquals(network.getName(), env.privateNetwork.getName());
+        assertEquals(network.getType(), env.privateNetwork.getType());
+    }
+
+    public void testGetAvailableTemplates()
+    {
+        List<VirtualMachineTemplate> templates = env.virtualDatacenter.listAvailableTemplates();
+        assertNotNull(templates);
+        assertFalse(templates.isEmpty());
+
+        template = templates.get(0);
+    }
+
+    @Test(dependsOnMethods = "testGetAvailableTemplates")
+    public void testFindAvailableTemplate()
+    {
+        VirtualMachineTemplate templateFound =
+            env.virtualDatacenter.findAvailableTemplate(VirtualMachineTemplatePredicates
+                .id(template.getId()));
+
+        assertNotNull(template);
+        assertNotNull(templateFound);
+        assertEquals(templateFound.getId(), template.getId());
+    }
+
+    @Test(dependsOnMethods = "testGetAvailableTemplates")
+    public void testGetAvailableTemplate()
+    {
+        VirtualMachineTemplate templateFound =
+            env.virtualDatacenter.getAvailableTemplate(template.getId());
+        assertNotNull(templateFound);
+        assertEquals(templateFound.getId(), template.getId());
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveApiTest.java
new file mode 100644
index 0000000..1416d81
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveApiTest.java
@@ -0,0 +1,142 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualMachineDto;
+import com.abiquo.server.core.cloud.VirtualMachineState;
+
+/**
+ * Live integration tests for the {@link VirtualMachine} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "VirtualMachineLiveApiTest")
+public class VirtualMachineLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testHasDataFromNode()
+    {
+        assertNotNull(env.virtualMachine.getNameLabel());
+        assertNotNull(env.virtualMachine.getInternalName());
+        assertNotNull(env.virtualMachine.getOwnerName());
+    }
+
+    public void testUpdateInfoFromNode()
+    {
+        env.virtualMachine.setNameLabel(PREFIX + "-label-updated");
+        env.virtualMachine.update();
+        env.virtualMachine.refresh();
+
+        assertEquals(env.virtualMachine.getNameLabel(), PREFIX + "-label-updated");
+    }
+
+    public void testGetTasks()
+    {
+        List<AsyncTask> tasks = env.virtualMachine.listTasks();
+        assertNotNull(tasks);
+    }
+
+    public void testGetState()
+    {
+        VirtualMachineState state = env.virtualMachine.getState();
+        assertEquals(state, VirtualMachineState.NOT_ALLOCATED);
+    }
+
+    public void testIsPersistent()
+    {
+        assertFalse(env.virtualMachine.isPersistent());
+    }
+
+    public void testGetVirtualAppliance()
+    {
+        VirtualAppliance vapp = env.virtualMachine.getVirtualAppliance();
+        assertNotNull(vapp);
+        assertEquals(vapp.getId(), env.virtualAppliance.getId());
+    }
+
+    public void testRebootVirtualMachineFailsWhenNotAllocated()
+    {
+        // Since the virtual machine is not deployed, this should not generate a task
+
+        try
+        {
+            env.virtualMachine.reboot();
+            fail("Reboot should have failed for the NOT_ALLOCATED virtual machine");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "VM-11");
+        }
+    }
+
+    public void testUpdateForcingLimits()
+    {
+        int originalHard = env.virtualDatacenter.getCpuCountHardLimit();
+        int originalSoft = env.virtualDatacenter.getCpuCountSoftLimit();
+
+        env.virtualDatacenter.setCpuCountHardLimit(10);
+        env.virtualDatacenter.setCpuCountSoftLimit(5);
+        env.virtualDatacenter.update();
+
+        try
+        {
+            VirtualMachine vm = env.virtualAppliance.getVirtualMachine(env.virtualMachine.getId());
+            vm.setCpu(7);
+            AsyncTask task = vm.update(true);
+
+            assertNull(task);
+            assertEquals(vm.getCpu(), 7);
+        }
+        finally
+        {
+            env.virtualDatacenter.setCpuCountHardLimit(originalHard);
+            env.virtualDatacenter.setCpuCountSoftLimit(originalSoft);
+            env.virtualDatacenter.update();
+        }
+    }
+
+    public void testAttachDvd()
+    {
+        VirtualMachine vm =
+            VirtualMachine.Builder.fromVirtualMachine(env.virtualMachine).dvd(true).build();
+        vm.save();
+
+        VirtualMachineDto updated =
+            env.cloudApi.getVirtualMachine(env.virtualAppliance.unwrap(), vm.getId());
+
+        assertNotNull(updated.getDvd());
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineNetworkingLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineNetworkingLiveApiTest.java
new file mode 100644
index 0000000..0a82a9b
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineNetworkingLiveApiTest.java
@@ -0,0 +1,241 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.network.ExternalIp;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PublicIp;
+import org.jclouds.abiquo.domain.network.PublicNetwork;
+import org.jclouds.abiquo.domain.network.UnmanagedIp;
+import org.jclouds.abiquo.domain.network.UnmanagedNetwork;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.network.IpPredicates;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Live integration tests for the {@link VirtualMachine} networking operations.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "VirtualMachineNetworkingLiveApiTest")
+public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private PrivateIp privateIp;
+
+    private ExternalIp externalIp;
+
+    private PublicIp publicIpInfrastructure;
+
+    private PublicIp publicIpCloud;
+
+    private UnmanagedIp unmanagedIp1;
+
+    private UnmanagedIp unmanagedIp2;
+
+    @BeforeClass
+    public void setupIps()
+    {
+        privateIp = env.privateNetwork.listUnusedIps().get(0);
+        assertNotNull(privateIp);
+
+        externalIp = env.externalNetwork.listUnusedIps().get(0);
+        assertNotNull(externalIp);
+
+        publicIpInfrastructure = env.virtualDatacenter.listAvailablePublicIps().get(0);
+        env.virtualDatacenter.purchasePublicIp(publicIpInfrastructure);
+
+        publicIpCloud =
+            env.virtualDatacenter.findPurchasedPublicIp(IpPredicates
+                .<PublicIp> address(publicIpInfrastructure.getIp()));
+        assertNotNull(publicIpCloud);
+    }
+
+    @AfterClass
+    public void restorePrivateIp()
+    {
+        AsyncTask task = env.virtualMachine.setNics(Lists.<Ip< ? , ? >> newArrayList(privateIp));
+        assertNull(task);
+
+        List<Ip< ? , ? >> nics = env.virtualMachine.listAttachedNics();
+        assertEquals(nics.size(), 1);
+        assertEquals(nics.get(0).getId(), privateIp.getId());
+
+        String address = publicIpCloud.getIp();
+        env.virtualDatacenter.releaseePublicIp(publicIpCloud);
+        assertNull(env.virtualDatacenter.findPurchasedPublicIp(IpPredicates
+            .<PublicIp> address(address)));
+    }
+
+    // TODO: Infrastructure edit link for public ips can not be used to attach
+    @Test(enabled = false)
+    public void testAttachInfrastructurePublicIp()
+    {
+        AsyncTask task =
+            env.virtualMachine.setNics(Lists.<Ip< ? , ? >> newArrayList(publicIpInfrastructure));
+        assertNull(task);
+
+        List<Ip< ? , ? >> nics = env.virtualMachine.listAttachedNics();
+        assertEquals(nics.size(), 1);
+        assertEquals(nics.get(0).getId(), publicIpInfrastructure.getId());
+    }
+
+    public void testAttachPublicIp()
+    {
+        AsyncTask task =
+            env.virtualMachine.setNics(Lists.<Ip< ? , ? >> newArrayList(publicIpCloud));
+        assertNull(task);
+
+        List<Ip< ? , ? >> nics = env.virtualMachine.listAttachedNics();
+        assertEquals(nics.size(), 1);
+        assertEquals(nics.get(0).getId(), publicIpCloud.getId());
+    }
+
+    @Test(dependsOnMethods = "testAttachPublicIp")
+    public void testAttachPrivateIp()
+    {
+        List<Ip< ? , ? >> nics = env.virtualMachine.listAttachedNics();
+        nics.add(privateIp);
+
+        AsyncTask task = env.virtualMachine.setNics(nics);
+        assertNull(task);
+
+        nics = env.virtualMachine.listAttachedNics();
+        assertEquals(nics.size(), 2);
+        assertEquals(nics.get(0).getId(), publicIpCloud.getId());
+        assertEquals(nics.get(1).getId(), privateIp.getId());
+    }
+
+    @Test(dependsOnMethods = "testAttachPrivateIp")
+    public void testAttachExternalIp()
+    {
+        List<Ip< ? , ? >> nics = env.virtualMachine.listAttachedNics();
+        nics.add(externalIp);
+
+        AsyncTask task = env.virtualMachine.setNics(nics);
+        assertNull(task);
+
+        nics = env.virtualMachine.listAttachedNics();
+        assertEquals(nics.size(), 3);
+        assertEquals(nics.get(0).getId(), publicIpCloud.getId());
+        assertEquals(nics.get(1).getId(), privateIp.getId());
+        assertEquals(nics.get(2).getId(), externalIp.getId());
+    }
+
+    @Test(dependsOnMethods = "testAttachExternalIp")
+    public void testAddUnmanagedNics()
+    {
+        List<Ip< ? , ? >> nics = env.virtualMachine.listAttachedNics();
+
+        AsyncTask task =
+            env.virtualMachine.setNics(nics,
+                Lists.<UnmanagedNetwork> newArrayList(env.unmanagedNetwork, env.unmanagedNetwork));
+        assertNull(task);
+
+        nics = env.virtualMachine.listAttachedNics();
+        assertEquals(nics.size(), 5);
+        assertEquals(nics.get(0).getId(), publicIpCloud.getId());
+        assertEquals(nics.get(1).getId(), privateIp.getId());
+        assertEquals(nics.get(2).getId(), externalIp.getId());
+        // Unmanaged ips are created during the attach.
+        assertEquals(nics.get(3).getNetworkName(), env.unmanagedNetwork.getName());
+        assertEquals(nics.get(4).getNetworkName(), env.unmanagedNetwork.getName());
+
+        unmanagedIp1 = (UnmanagedIp) nics.get(3);
+        unmanagedIp2 = (UnmanagedIp) nics.get(4);
+    }
+
+    @Test(dependsOnMethods = "testAddUnmanagedNics")
+    public void testReorderNics()
+    {
+        List<Ip< ? , ? >> nics = env.virtualMachine.listAttachedNics();
+
+        AsyncTask task =
+            env.virtualMachine.setNics(Lists.<Ip< ? , ? >> newArrayList(nics.get(2), nics.get(1),
+                nics.get(0), nics.get(4), nics.get(3)));
+        assertNull(task);
+
+        nics = env.virtualMachine.listAttachedNics();
+        assertEquals(nics.size(), 5);
+        assertEquals(nics.get(0).getId(), externalIp.getId());
+        assertEquals(nics.get(1).getId(), privateIp.getId());
+        assertEquals(nics.get(2).getId(), publicIpCloud.getId());
+        assertEquals(nics.get(3).getId(), unmanagedIp2.getId());
+        assertEquals(nics.get(4).getId(), unmanagedIp1.getId());
+    }
+
+    @Test(dependsOnMethods = "testReorderNics")
+    public void testDetachNics()
+    {
+        List<Ip< ? , ? >> nics = env.virtualMachine.listAttachedNics();
+
+        AsyncTask task =
+            env.virtualMachine.setNics(Lists.<Ip< ? , ? >> newArrayList(nics.get(1), nics.get(2)));
+        assertNull(task);
+
+        nics = env.virtualMachine.listAttachedNics();
+        assertEquals(nics.size(), 2);
+        assertEquals(nics.get(0).getId(), privateIp.getId());
+        assertEquals(nics.get(1).getId(), publicIpCloud.getId());
+    }
+
+    @Test(dependsOnMethods = "testDetachNics")
+    public void testSetDefaultGateway()
+    {
+        PublicNetwork network = publicIpCloud.getNetwork();
+        env.virtualMachine.setGatewayNetwork(network);
+
+        Integer configId = env.virtualMachine.unwrap().getIdFromLink("network_configuration");
+        assertEquals(configId, network.getId());
+    }
+
+    // TODO: Review this functionality
+    @Test(dependsOnMethods = "testSetDefaultGateway", enabled = false)
+    public void testDetachAllNics()
+    {
+        try
+        {
+            env.virtualMachine.setNics(null);
+
+            fail("It should not be allowed to remove all nics from a vm");
+        }
+        catch (AbiquoException ex)
+        {
+            // At least one nic must be configured
+            assertHasError(ex, Status.BAD_REQUEST, "VM-46");
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineStorageLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineStorageLiveApiTest.java
new file mode 100644
index 0000000..074f4028
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineStorageLiveApiTest.java
@@ -0,0 +1,159 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.jclouds.abiquo.domain.infrastructure.Tier;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.infrastructure.TierPredicates;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the {@link VirtualMachine} storage operations.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "VirtualMachineStorageLiveApiTest")
+public class VirtualMachineStorageLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private Volume volume;
+
+    private HardDisk hardDisk;
+
+    public void testAttachVolumes()
+    {
+        volume = createVolume();
+
+        // Since the virtual machine is not deployed, this should not generate a task
+        AsyncTask task = env.virtualMachine.attachVolumes(volume);
+        assertNull(task);
+
+        List<Volume> attached = env.virtualMachine.listAttachedVolumes();
+        assertEquals(attached.size(), 1);
+        assertEquals(attached.get(0).getId(), volume.getId());
+    }
+
+    @Test(dependsOnMethods = "testAttachVolumes")
+    public void detachVolume()
+    {
+        env.virtualMachine.detachVolumes(volume);
+        List<Volume> attached = env.virtualMachine.listAttachedVolumes();
+        assertTrue(attached.isEmpty());
+    }
+
+    @Test(dependsOnMethods = "detachVolume")
+    public void detachAllVolumes()
+    {
+        // Since the virtual machine is not deployed, this should not generate a task
+        AsyncTask task = env.virtualMachine.attachVolumes(volume);
+        assertNull(task);
+
+        env.virtualMachine.detachAllVolumes();
+        List<Volume> attached = env.virtualMachine.listAttachedVolumes();
+        assertTrue(attached.isEmpty());
+
+        deleteVolume(volume);
+    }
+
+    public void testAttachHardDisks()
+    {
+        hardDisk = createHardDisk();
+
+        // Since the virtual machine is not deployed, this should not generate a task
+        AsyncTask task = env.virtualMachine.attachHardDisks(hardDisk);
+        assertNull(task);
+
+        List<HardDisk> attached = env.virtualMachine.listAttachedHardDisks();
+        assertEquals(attached.size(), 1);
+        assertEquals(attached.get(0).getId(), hardDisk.getId());
+    }
+
+    @Test(dependsOnMethods = "testAttachHardDisks")
+    public void detachHardDisk()
+    {
+        env.virtualMachine.detachHardDisks(hardDisk);
+        List<HardDisk> attached = env.virtualMachine.listAttachedHardDisks();
+        assertTrue(attached.isEmpty());
+    }
+
+    @Test(dependsOnMethods = "detachHardDisk")
+    public void detachAllHardDisks()
+    {
+        // Since the virtual machine is not deployed, this should not generate a task
+        AsyncTask task = env.virtualMachine.attachHardDisks(hardDisk);
+        assertNull(task);
+
+        env.virtualMachine.detachAllHardDisks();
+        List<HardDisk> attached = env.virtualMachine.listAttachedHardDisks();
+        assertTrue(attached.isEmpty());
+
+        deleteHardDisk(hardDisk);
+    }
+
+    private Volume createVolume()
+    {
+        Tier tier = env.virtualDatacenter.findStorageTier(TierPredicates.name(env.tier.getName()));
+
+        Volume volume =
+            Volume.builder(env.context.getApiContext(), env.virtualDatacenter, tier)
+                .name(PREFIX + "Hawaian volume").sizeInMb(32).build();
+        volume.save();
+
+        assertNotNull(volume.getId());
+        assertNotNull(env.virtualDatacenter.getVolume(volume.getId()));
+
+        return volume;
+    }
+
+    private void deleteVolume(final Volume volume)
+    {
+        Integer id = volume.getId();
+        volume.delete();
+        assertNull(env.virtualDatacenter.getVolume(id));
+    }
+
+    private HardDisk createHardDisk()
+    {
+        HardDisk hardDisk =
+            HardDisk.builder(env.context.getApiContext(), env.virtualDatacenter).sizeInMb(64L)
+                .build();
+        hardDisk.save();
+
+        assertNotNull(hardDisk.getId());
+        assertNotNull(hardDisk.getSequence());
+
+        return hardDisk;
+    }
+
+    private void deleteHardDisk(final HardDisk hardDisk)
+    {
+        Integer id = hardDisk.getId();
+        hardDisk.delete();
+        assertNull(env.virtualDatacenter.getHardDisk(id));
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplateLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplateLiveApiTest.java
new file mode 100644
index 0000000..7391cf5
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplateLiveApiTest.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.config.Category;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the {@link VirtualMachineTemplate} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "VirtualMachineTemplateLiveApiTest")
+public class VirtualMachineTemplateLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testGetParent()
+    {
+        Datacenter datacenter = env.virtualMachine.getTemplate().getDatacenter();
+        assertNotNull(datacenter);
+        assertEquals(datacenter.getId(), env.datacenter.getId());
+    }
+
+    public void testGetCategory()
+    {
+        Category category = env.virtualMachine.getTemplate().getCategory();
+        assertNotNull(category);
+    }
+
+    public void testRequestConversionToSameFormat()
+    {
+        try
+        {
+            env.virtualMachine.getTemplate().requestConversion(
+                env.virtualMachine.getTemplate().getDiskFormatType());
+            fail("Should not be able to create create a conversion to the base format");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "CONVERSION-3");
+        }
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VolumeLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VolumeLiveApiTest.java
new file mode 100644
index 0000000..1a85ea0
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VolumeLiveApiTest.java
@@ -0,0 +1,145 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.cloud;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.jclouds.abiquo.domain.cloud.options.VolumeOptions;
+import org.jclouds.abiquo.domain.infrastructure.Tier;
+import org.jclouds.abiquo.domain.network.PrivateNetwork;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.cloud.VolumePredicates;
+import org.jclouds.abiquo.predicates.infrastructure.TierPredicates;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+
+/**
+ * Live integration tests for the {@link Volume} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "VolumeLiveApiTest")
+public class VolumeLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testCreateVolume()
+    {
+        // We need the vdc-relative tier
+        Tier tier = env.virtualDatacenter.findStorageTier(TierPredicates.name(env.tier.getName()));
+
+        Volume volume =
+            Volume.builder(env.context.getApiContext(), env.virtualDatacenter, tier)
+                .name(PREFIX + "Hawaian volume").sizeInMb(32).build();
+        volume.save();
+
+        assertNotNull(volume.getId());
+        assertNotNull(env.virtualDatacenter.getVolume(volume.getId()));
+    }
+
+    @Test(dependsOnMethods = "testCreateVolume")
+    public void testFilterVolumes()
+    {
+        VolumeOptions validOptions = VolumeOptions.builder().has("hawa").build();
+        VolumeOptions invalidOptions = VolumeOptions.builder().has("cacatua").build();
+
+        List<VolumeManagementDto> volumes =
+            env.cloudApi.listVolumes(env.virtualDatacenter.unwrap(), validOptions).getCollection();
+
+        assertEquals(volumes.size(), 1);
+
+        volumes =
+            env.cloudApi.listVolumes(env.virtualDatacenter.unwrap(), invalidOptions)
+                .getCollection();
+
+        assertEquals(volumes.size(), 0);
+    }
+
+    @Test(dependsOnMethods = "testFilterVolumes")
+    public void testUpdateVolume()
+    {
+        Volume volume =
+            env.virtualDatacenter.findVolume(VolumePredicates.name(PREFIX + "Hawaian volume"));
+        assertNotNull(volume);
+
+        volume.setName("Hawaian volume updated");
+        AsyncTask task = volume.update();
+        assertNull(task);
+
+        // Reload the volume to check
+        Volume updated = env.virtualDatacenter.getVolume(volume.getId());
+        assertEquals(updated.getName(), "Hawaian volume updated");
+    }
+
+    @Test(dependsOnMethods = "testUpdateVolume")
+    public void testMoveVolume()
+    {
+        // Create the new virtual datacenter
+        PrivateNetwork network =
+            PrivateNetwork.builder(env.context.getApiContext()).name("DefaultNetwork")
+                .gateway("192.168.1.1").address("192.168.1.0").mask(24).build();
+
+        VirtualDatacenter newVdc =
+            VirtualDatacenter.builder(env.context.getApiContext(), env.datacenter, env.enterprise)
+                .name("New VDC").network(network).hypervisorType(env.machine.getType()).build();
+        newVdc.save();
+        assertNotNull(newVdc.getId());
+
+        Volume volume =
+            env.virtualDatacenter.findVolume(VolumePredicates.name("Hawaian volume updated"));
+        assertNotNull(volume);
+
+        volume.moveTo(newVdc);
+
+        // Check that the underlying Dto has been updated to the new VDC
+        assertTrue(volume.unwrap().getEditLink().getHref()
+            .startsWith(newVdc.unwrap().getEditLink().getHref()));
+
+        // Move it back to the original VDC
+        volume.moveTo(env.virtualDatacenter);
+
+        // Check that the underlying Dto has been updated to the new VDC
+        assertTrue(volume.unwrap().getEditLink().getHref()
+            .startsWith(env.virtualDatacenter.unwrap().getEditLink().getHref()));
+
+        // Tear down the virtual datacenter
+        newVdc.delete();
+    }
+
+    @Test(dependsOnMethods = "testMoveVolume")
+    public void testDeleteVolume()
+    {
+        Volume volume =
+            env.virtualDatacenter.findVolume(VolumePredicates.name("Hawaian volume updated"));
+        assertNotNull(volume);
+
+        Integer id = volume.getId();
+        volume.delete();
+
+        assertNull(env.virtualDatacenter.getVolume(id));
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/CategoryLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/CategoryLiveApiTest.java
new file mode 100644
index 0000000..6ce6d7d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/CategoryLiveApiTest.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.config.CategoryPredicates;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the {@link Category} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "CategoryLiveApiTest")
+public class CategoryLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testCreateAndGet()
+    {
+        Category category =
+            Category.builder(env.context.getApiContext()).name(PREFIX + "-test-category").build();
+        category.save();
+
+        Category apiCategory =
+            env.context.getAdministrationService().findCategory(
+                CategoryPredicates.name(PREFIX + "-test-category"));
+        assertNotNull(apiCategory);
+        assertEquals(category.getName(), apiCategory.getName());
+
+        apiCategory.delete();
+    }
+
+    @Test(dependsOnMethods = "testCreateAndGet")
+    public void testUpdate()
+    {
+        Iterable<Category> categories = env.context.getAdministrationService().listCategories();
+        assertNotNull(categories);
+
+        Category category = categories.iterator().next();
+        String name = category.getName();
+
+        category.setName(PREFIX + "-test-category-updated");
+        category.update();
+
+        Category apiCategory =
+            env.context.getAdministrationService().findCategory(
+                CategoryPredicates.name(PREFIX + "-test-category-updated"));
+
+        assertNotNull(apiCategory);
+        assertEquals(PREFIX + "-test-category-updated", apiCategory.getName());
+
+        category.setName(name);
+        category.update();
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/CurrencyLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/CurrencyLiveApiTest.java
new file mode 100644
index 0000000..4e0bd13
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/CurrencyLiveApiTest.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.config.CurrencyPredicates;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the {@link Currency} domain class.
+ * 
+ * @author Susana Acedo
+ */
+@Test(groups = "api", testName = "CurrencyLiveApiTest")
+public class CurrencyLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testCreateAndGet()
+    {
+        Currency currency =
+            Currency.builder(env.context.getApiContext()).name(PREFIX + "test-currency")
+                .symbol("test-$").digits(2).build();
+        currency.save();
+
+        Currency apiCurrency =
+            env.context.getPricingService().findCurrency(
+                CurrencyPredicates.name(PREFIX + "test-currency"));
+        assertNotNull(apiCurrency);
+        assertEquals(currency.getName(), apiCurrency.getName());
+
+        apiCurrency.delete();
+    }
+
+    @Test(dependsOnMethods = "testCreateAndGet")
+    public void testUpdate()
+    {
+        Iterable<Currency> currencies = env.context.getPricingService().listCurrencies();
+        assertNotNull(currencies);
+
+        Currency currency = currencies.iterator().next();
+        String name = currency.getName();
+
+        currency.setName(PREFIX + "t-currency-upd");
+        currency.update();
+
+        Currency apiCurrency =
+            env.context.getPricingService().findCurrency(
+                CurrencyPredicates.name(PREFIX + "t-currency-upd"));
+
+        assertNotNull(apiCurrency);
+        assertEquals(PREFIX + "t-currency-upd", apiCurrency.getName());
+
+        currency.setName(name);
+        currency.update();
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/LicenseLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/LicenseLiveApiTest.java
new file mode 100644
index 0000000..769412c
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/LicenseLiveApiTest.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.fail;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the {@link User} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "LicenseLiveApiTest")
+public class LicenseLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testCreateRepeated()
+    {
+        License repeated = License.Builder.fromLicense(env.license).build();
+
+        try
+        {
+            repeated.add();
+            fail("Should not be able to create licenses with the same code");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "LICENSE-5");
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/SystemPropertiesLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/SystemPropertiesLiveApiTest.java
new file mode 100644
index 0000000..9652665
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/config/SystemPropertiesLiveApiTest.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.config;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the {@link User} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "SystemPropertiesLiveApiTest")
+public class SystemPropertiesLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testUpdate()
+    {
+        SystemProperty prop =
+            env.administrationService.getSystemProperty("client.dashboard.showStartUpAlert");
+
+        String value = prop.getValue();
+        prop.setValue("0");
+        prop.update();
+
+        // Recover the updated datacenter
+        SystemProperty updated =
+            env.administrationService.getSystemProperty("client.dashboard.showStartUpAlert");
+
+        assertEquals(updated.getValue(), "0");
+
+        prop.setValue(value);
+        prop.update();
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/EnterpriseLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/EnterpriseLiveApiTest.java
new file mode 100644
index 0000000..972c98e
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/EnterpriseLiveApiTest.java
@@ -0,0 +1,190 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.enterprise.Enterprise.Builder;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+
+/**
+ * Live integration tests for the {@link Enterprise} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "EnterpriseLiveApiTest")
+public class EnterpriseLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private Enterprise enterprise;
+
+    private Limits limits;
+
+    @BeforeClass
+    public void setupEnterprise()
+    {
+        enterprise = Enterprise.Builder.fromEnterprise(env.enterprise).build();
+        enterprise.setName(PREFIX + "-enterprise-test");
+        enterprise.save();
+
+        limits = enterprise.allowDatacenter(env.datacenter);
+        assertNotNull(limits);
+
+        DatacentersLimitsDto limitsDto =
+            env.enterpriseApi.getLimits(enterprise.unwrap(), env.datacenter.unwrap());
+        assertNotNull(limitsDto);
+        assertEquals(limitsDto.getCollection().size(), 1);
+    }
+
+    @AfterClass
+    public void tearDownEnterprise()
+    {
+        enterprise.prohibitDatacenter(env.datacenter);
+
+        try
+        {
+            // If a datacenter is not allowed, the limits for it can not be retrieved
+            env.enterpriseApi.getLimits(enterprise.unwrap(), env.datacenter.unwrap());
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "ENTERPRISE-10");
+        }
+
+        List<Datacenter> allowed = enterprise.listAllowedDatacenters();
+        assertNotNull(allowed);
+        assertTrue(allowed.isEmpty());
+
+        enterprise.delete();
+    }
+
+    public void testUpdate()
+    {
+        enterprise.setName("Updated Enterprise");
+        enterprise.update();
+
+        // Recover the updated enterprise
+        EnterpriseDto updated = env.enterpriseApi.getEnterprise(enterprise.getId());
+
+        assertEquals(updated.getName(), "Updated Enterprise");
+    }
+
+    public void testCreateRepeated()
+    {
+        Enterprise repeated = Builder.fromEnterprise(enterprise).build();
+
+        try
+        {
+            repeated.save();
+            fail("Should not be able to create enterprises with the same name");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "ENTERPRISE-4");
+        }
+    }
+
+    public void testAllowTwiceWorks()
+    {
+        // Allow the datacenter again and check that the configuration has not changed
+        Limits limits = enterprise.allowDatacenter(env.datacenter);
+        assertNotNull(limits);
+
+        DatacentersLimitsDto limitsDto =
+            env.enterpriseApi.getLimits(enterprise.unwrap(), env.datacenter.unwrap());
+        assertNotNull(limitsDto);
+        assertEquals(limitsDto.getCollection().size(), 1);
+    }
+
+    public void testListLimits()
+    {
+        List<Limits> allLimits = enterprise.listLimits();
+        assertNotNull(allLimits);
+        assertEquals(allLimits.size(), 1);
+    }
+
+    public void testUpdateInvalidLimits()
+    {
+        // CPU soft remains to 0 => conflict because hard is smaller
+        limits.setCpuCountHardLimit(2);
+
+        try
+        {
+            limits.update();
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.BAD_REQUEST, "CONSTR-LIMITRANGE");
+        }
+    }
+
+    public void testUpdateLimits()
+    {
+        limits.setCpuCountLimits(4, 5);
+        limits.update();
+
+        DatacentersLimitsDto limitsDto =
+            env.enterpriseApi.getLimits(enterprise.unwrap(), env.datacenter.unwrap());
+        assertNotNull(limitsDto);
+        assertEquals(limitsDto.getCollection().size(), 1);
+        assertEquals(limitsDto.getCollection().get(0).getCpuCountHardLimit(), 5);
+        assertEquals(limitsDto.getCollection().get(0).getCpuCountSoftLimit(), 4);
+    }
+
+    public void testListAllowedDatacenters()
+    {
+        List<Datacenter> allowed = enterprise.listAllowedDatacenters();
+
+        assertNotNull(allowed);
+        assertFalse(allowed.isEmpty());
+        assertEquals(allowed.get(0).getId(), env.datacenter.getId());
+    }
+
+    public void testListVirtualMachines()
+    {
+        List<VirtualMachine> machines = env.defaultEnterprise.listVirtualMachines();
+        assertTrue(machines.size() > 0);
+    }
+
+    public void testListVirtualAppliances()
+    {
+        List<VirtualAppliance> vapps = env.defaultEnterprise.listVirtualAppliances();
+        assertTrue(vapps.size() > 0);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/EnterprisePropertiesLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/EnterprisePropertiesLiveApiTest.java
new file mode 100644
index 0000000..8b6d4d7
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/EnterprisePropertiesLiveApiTest.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.enterprise.EnterprisePropertiesDto;
+
+/**
+ * Live integration tests for the {@link Enterprise} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "EnterprisePropertiesLiveApiTest")
+public class EnterprisePropertiesLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testUpdate()
+    {
+        EnterpriseProperties properties =
+            env.administrationService.getEnterpriseProperties(env.enterprise);
+
+        Integer size = properties.getProperties().size();
+        properties.getProperties().put("Prop", "Value");
+        properties.update();
+
+        // Recover the updated properties
+        EnterprisePropertiesDto updated =
+            env.enterpriseApi.getEnterpriseProperties(env.enterprise.unwrap());
+
+        assertEquals(updated.getProperties().size(), size + 1);
+        assertTrue(updated.getProperties().containsKey("Prop"));
+        assertTrue(updated.getProperties().containsValue("Value"));
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/TemplateDefinitionListLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/TemplateDefinitionListLiveApiTest.java
new file mode 100644
index 0000000..4b16195
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/TemplateDefinitionListLiveApiTest.java
@@ -0,0 +1,81 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.util.List;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.enterprise.TemplateDefinitionListPredicates;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live integration tests for the {@link TemplateDefinitionList} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "TemplateDefinitionListLiveApiTest")
+public class TemplateDefinitionListLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private TemplateDefinitionList list;
+
+    public void testUpdate()
+    {
+        list.setName(list.getName() + "Updated");
+        list.update();
+
+        List<TemplateDefinitionList> lists =
+            env.enterprise.listTemplateDefinitionLists(TemplateDefinitionListPredicates
+                .name("myListUpdated"));
+
+        assertEquals(lists.size(), 1);
+    }
+
+    public void testListStates()
+    {
+        List<TemplateState> states = list.listStatus(env.datacenter);
+        assertNotNull(states);
+    }
+
+    @BeforeClass
+    public void setup()
+    {
+        list =
+            TemplateDefinitionList.builder(env.context.getApiContext(), env.enterprise)
+                .name("myList").url("http://virtualapp-repository.com/vapp1.ovf").build();
+
+        list.save();
+
+        assertNotNull(list.getId());
+    }
+
+    @AfterClass
+    public void tearDown()
+    {
+        Integer idTemplateList = list.getId();
+        list.delete();
+        assertNull(env.enterprise.getTemplateDefinitionList(idTemplateList));
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/UserLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/UserLiveApiTest.java
new file mode 100644
index 0000000..57b524a
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/enterprise/UserLiveApiTest.java
@@ -0,0 +1,109 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.enterprise;
+
+import static org.jclouds.abiquo.predicates.enterprise.UserPredicates.nick;
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.enterprise.UserPredicates;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.enterprise.UserDto;
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link User} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "UserLiveApiTest")
+public class UserLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testUpdate()
+    {
+        String username = env.user.getName();
+        env.user.setName("Manolo");
+        env.user.update();
+
+        // Recover the updated user
+        UserDto updated = env.enterpriseApi.getUser(env.enterprise.unwrap(), env.user.getId());
+
+        assertEquals(updated.getName(), "Manolo");
+
+        env.user.setName(username);
+        env.user.update();
+    }
+
+    public void testCreateRepeated()
+    {
+        User repeated = User.Builder.fromUser(env.user).build();
+
+        try
+        {
+            repeated.save();
+            fail("Should not be able to create users with the same nick");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "USER-4");
+        }
+    }
+
+    public void testChangeRoleAndUpdate()
+    {
+        env.user.setRole(env.anotherRole);
+        env.user.update();
+
+        Role role2 = env.enterprise.findUser(UserPredicates.nick(env.user.getNick())).getRole();
+
+        assertEquals(env.anotherRole.getId(), role2.getId());
+        assertEquals(role2.getName(), "Another role");
+
+        env.user.setRole(env.role);
+        env.user.update();
+    }
+
+    public void testListUser()
+    {
+        Iterable<User> users = env.enterprise.listUsers();
+        assertEquals(Iterables.size(users), 2);
+
+        users = env.enterprise.listUsers(nick(env.user.getNick()));
+        assertEquals(Iterables.size(users), 1);
+
+        users = env.enterprise.listUsers(nick(env.user.getName() + "FAIL"));
+        assertEquals(Iterables.size(users), 0);
+    }
+
+    public void testGetCurrentUser()
+    {
+        User user = env.context.getAdministrationService().getCurrentUser();
+        assertNotNull(user);
+        assertEquals(user.getNick(), env.context.getApiContext().getIdentity());
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/event/EventLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/event/EventLiveApiTest.java
new file mode 100644
index 0000000..a82bc2b
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/event/EventLiveApiTest.java
@@ -0,0 +1,283 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.event;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.Volume;
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.domain.event.options.EventOptions;
+import org.jclouds.abiquo.domain.infrastructure.Tier;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.infrastructure.TierPredicates;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.ComponentType;
+import com.abiquo.model.enumerator.EventType;
+import com.abiquo.model.enumerator.SeverityType;
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link Event} domain class.
+ * 
+ * @author Vivien Mahé
+ */
+@Test(groups = "api", testName = "EventLiveApiTest")
+public class EventLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testListEventsFilteredByDatacenter()
+    {
+        String name = randomName();
+        env.datacenter.setName(name);
+        env.datacenter.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).datacenterName(name).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByRack()
+    {
+        String name = randomName();
+        env.rack.setName(name);
+        env.rack.update();
+
+        EventOptions options = EventOptions.builder().dateFrom(new Date()).rackName(name).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByPM()
+    {
+        String name = randomName();
+        env.machine.setName(name);
+        env.machine.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).physicalMachineName(name).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByStorageDevice()
+    {
+        String name = randomName();
+        env.storageDevice.setName(name);
+        env.storageDevice.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).storageSystemName(name).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByStoragePool()
+    {
+        Tier tier = env.datacenter.findTier(TierPredicates.name("Default Tier 2"));
+        assertNotNull(tier);
+
+        try
+        {
+            env.storagePool.setTier(tier);
+            env.storagePool.update();
+
+            EventOptions options =
+                EventOptions.builder().dateFrom(new Date())
+                    .storagePoolName(env.storagePool.getName()).build();
+            assertEvents(options);
+        }
+        finally
+        {
+            // Restore the original tier
+            env.storagePool.setTier(env.tier);
+            env.storagePool.update();
+        }
+    }
+
+    public void testListEventsFilteredByEnterprise()
+    {
+        String entName = env.enterprise.getName();
+        String name = randomName();
+        env.enterprise.setName(name);
+        env.enterprise.update();
+
+        // Enterprise current =
+        // env.enterpriseAdminContext.getAdministrationService().getCurrentEnterprise();
+        // current.setName("Enterprise updated");
+        // current.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).enterpriseName(name).build();
+        assertEvents(options);
+
+        env.enterprise.setName(entName);
+        env.enterprise.update();
+    }
+
+    /**
+     * TODO: Using the painUserContext, modifying the user returns this error: HTTP/1.1 401
+     * Unauthorized
+     **/
+    @Test(enabled = false)
+    public void testListEventsFilteredByUser()
+    {
+        User current = env.plainUserContext.getAdministrationService().getCurrentUser();
+        current.setEmail("test@test.com");
+        current.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).userName(current.getName()).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByVDC()
+    {
+        String name = randomName();
+        env.virtualDatacenter.setName(name);
+        env.virtualDatacenter.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).virtualDatacenterName(name).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByVapp()
+    {
+        String name = randomName();
+        env.virtualAppliance.setName(name);
+        env.virtualAppliance.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).virtualAppName(name).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByVM()
+    {
+        VirtualMachine vm = createVirtualMachine();
+        vm.delete();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).actionPerformed(EventType.VM_DELETE)
+                .build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByVolume()
+    {
+        String name = randomName();
+        Volume volume = createVolume();
+        volume.setName(name);
+        volume.update();
+        volume.delete(); // We don't need it any more. events already exist
+
+        EventOptions options = EventOptions.builder().dateFrom(new Date()).volumeName(name).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredBySeverity()
+    {
+        String name = randomName();
+        env.virtualAppliance.setName(name);
+        env.virtualAppliance.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).virtualAppName(name)
+                .severity(SeverityType.INFO).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByActionPerformed()
+    {
+        String name = randomName();
+        env.virtualAppliance.setName(name);
+        env.virtualAppliance.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).virtualAppName(name)
+                .actionPerformed(EventType.VAPP_MODIFY).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByComponent()
+    {
+        String name = randomName();
+        env.virtualAppliance.setName(name);
+        env.virtualAppliance.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).virtualAppName(name)
+                .component(ComponentType.VIRTUAL_APPLIANCE).build();
+        assertEvents(options);
+    }
+
+    public void testListEventsFilteredByDescription()
+    {
+        String name = randomName();
+        env.virtualAppliance.setName(name);
+        env.virtualAppliance.update();
+
+        EventOptions options =
+            EventOptions.builder().dateFrom(new Date()).virtualAppName(name)
+                .description("Virtual appliance '" + name + "' has been modified.").build();
+        assertEvents(options);
+    }
+
+    // Helpers
+
+    private void assertEvents(final EventOptions options)
+    {
+        Iterable<Event> events = env.eventService.listEvents(options);
+        assertTrue(Iterables.size(events) >= 1);
+    }
+
+    private Volume createVolume()
+    {
+        Tier tier = env.virtualDatacenter.findStorageTier(TierPredicates.name(env.tier.getName()));
+        Volume volume =
+            Volume.builder(env.context.getApiContext(), env.virtualDatacenter, tier)
+                .name(PREFIX + "Event vol").sizeInMb(32).build();
+
+        volume.save();
+        assertNotNull(volume.getId());
+
+        return volume;
+    }
+
+    private VirtualMachine createVirtualMachine()
+    {
+        VirtualMachine virtualMachine =
+            VirtualMachine.builder(env.context.getApiContext(), env.virtualAppliance, env.template)
+                .cpu(2).ram(128).build();
+
+        virtualMachine.save();
+        assertNotNull(virtualMachine.getId());
+
+        return virtualMachine;
+    }
+
+    private static String randomName()
+    {
+        return PREFIX + UUID.randomUUID().toString().substring(0, 12);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/BladeLiveUcsTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/BladeLiveUcsTest.java
new file mode 100644
index 0000000..18aa3e9
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/BladeLiveUcsTest.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link Blade} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "ucs", testName = "BladeLiveUcsTest")
+public class BladeLiveUcsTest extends BaseAbiquoApiLiveApiTest
+{
+    Blade blade;
+
+    public void testFindAvailableVirtualSwitch()
+    {
+        String vswitch = blade.getAvailableVirtualSwitches().get(0);
+        String found = blade.findAvailableVirtualSwitch(vswitch);
+        assertEquals(found, vswitch);
+    }
+
+    public void testGetRack()
+    {
+        ManagedRack rack = blade.getRack();
+        assertNotNull(rack);
+        assertEquals(rack.getId(), env.ucsRack.getId());
+    }
+
+    public void testListBlades()
+    {
+        Iterable<Blade> blades = env.ucsRack.listMachines();
+        assertTrue(Iterables.size(blades) > 0);
+    }
+
+    public void testGetLogicServer()
+    {
+        LogicServer logicServer = blade.getLogicServer();
+        assertNotNull(logicServer);
+        assertNotNull(logicServer.getName());
+    }
+
+    public void testLedOn()
+    {
+        blade.ledOn();
+        BladeLocatorLed led = blade.getLocatorLed();
+        assertNotNull(led);
+        assertEquals(led.getAdminStatus(), "on");
+    }
+
+    public void testLedOff()
+    {
+        blade.ledOff();
+        BladeLocatorLed led = blade.getLocatorLed();
+        assertNotNull(led);
+        assertEquals(led.getAdminStatus(), "off");
+    }
+
+    @BeforeClass
+    public void setup()
+    {
+        blade = env.ucsRack.listMachines().get(0);
+        assertNotNull(blade);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/DatacenterLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/DatacenterLiveApiTest.java
new file mode 100644
index 0000000..650960d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/DatacenterLiveApiTest.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.enterprise.Limits;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter.Builder;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+
+/**
+ * Live integration tests for the {@link Datacenter} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "DatacenterLiveApiTest")
+public class DatacenterLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testUpdate()
+    {
+        env.datacenter.setLocation("New York");
+        env.datacenter.update();
+
+        // Recover the updated datacenter
+        DatacenterDto updated = env.infrastructureApi.getDatacenter(env.datacenter.getId());
+
+        assertEquals(updated.getLocation(), "New York");
+    }
+
+    public void testCheckHypervisorType()
+    {
+        HypervisorType type = env.datacenter.getHypervisorType(env.machine.getIp());
+
+        assertEquals(env.machine.getType(), type);
+    }
+
+    public void testCreateRepeated()
+    {
+        Datacenter repeated = Builder.fromDatacenter(env.datacenter).build();
+
+        try
+        {
+            repeated.save();
+            fail("Should not be able to create datacenters with the same name");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "DC-3");
+        }
+    }
+
+    public void testListLimits()
+    {
+        List<Limits> limits = env.datacenter.listLimits();
+        assertNotNull(limits);
+        assertTrue(limits.size() > 0);
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/MachineLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/MachineLiveApiTest.java
new file mode 100644
index 0000000..67c1d74
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/MachineLiveApiTest.java
@@ -0,0 +1,171 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.infrastructure.RemoteServicePredicates;
+import org.jclouds.abiquo.util.Config;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.MachineState;
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.abiquo.server.core.infrastructure.MachineDto;
+
+/**
+ * Live integration tests for the {@link Machine} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "MachineLiveApiTest")
+public class MachineLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testDiscoverMachineWithouRemoteService()
+    {
+        // Delete node collector
+        RemoteService nc =
+            env.datacenter.findRemoteService(RemoteServicePredicates
+                .type(RemoteServiceType.NODE_COLLECTOR));
+        nc.delete();
+
+        try
+        {
+            String ip = Config.get("abiquo.hypervisor.address");
+            HypervisorType type = HypervisorType.valueOf(Config.get("abiquo.hypervisor.type"));
+            String user = Config.get("abiquo.hypervisor.user");
+            String pass = Config.get("abiquo.hypervisor.pass");
+
+            env.datacenter.discoverSingleMachine(ip, type, user, pass);
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.NOT_FOUND, "RS-2");
+        }
+
+        URI endpoint = URI.create(env.context.getApiContext().getProviderMetadata().getEndpoint());
+
+        // Restore rs
+        nc =
+            RemoteService.builder(env.context.getApiContext(), env.datacenter)
+                .type(RemoteServiceType.NODE_COLLECTOR).ip(endpoint.getHost()).build();
+        nc.save();
+    }
+
+    public void testUpdate()
+    {
+        env.machine.setName("API Machine");
+        env.machine.update();
+
+        // Recover the updated machine
+        MachineDto updated =
+            env.infrastructureApi.getMachine(env.rack.unwrap(), env.machine.getId());
+        assertEquals(updated.getName(), "API Machine");
+    }
+
+    public void testCheck()
+    {
+        MachineState state = env.machine.check();
+
+        // Recover the machine with same state that has been returned
+        MachineDto machine =
+            env.infrastructureApi.getMachine(env.rack.unwrap(), env.machine.getId());
+        assertEquals(machine.getState(), state);
+    }
+
+    public void testCheckFromDatacenter()
+    {
+        String ip = Config.get("abiquo.hypervisor.address");
+        HypervisorType type = HypervisorType.valueOf(Config.get("abiquo.hypervisor.type"));
+        String user = Config.get("abiquo.hypervisor.user");
+        String pass = Config.get("abiquo.hypervisor.pass");
+
+        MachineState state = env.datacenter.checkMachineState(ip, type, user, pass);
+
+        // Recover the same machine and compare states
+        MachineDto machine =
+            env.infrastructureApi.getMachine(env.rack.unwrap(), env.machine.getId());
+        assertEquals(machine.getState(), state);
+    }
+
+    public void testFindDatastore()
+    {
+        Datastore datastore = env.machine.getDatastores().get(0);
+        Datastore found = env.machine.findDatastore(datastore.getName());
+        assertEquals(found.getName(), datastore.getName());
+    }
+
+    public void testFindAvailableVirtualSwitch()
+    {
+        String vswitch = env.machine.getAvailableVirtualSwitches().get(0);
+        String found = env.machine.findAvailableVirtualSwitch(vswitch);
+        assertEquals(found, vswitch);
+    }
+
+    public void testGetRack()
+    {
+        Rack rack = env.machine.getRack();
+        assertNotNull(rack);
+        assertEquals(rack.getId(), env.rack.getId());
+    }
+
+    public void testListVirtualMachines()
+    {
+        List<VirtualMachine> machines = env.machine.listRemoteVirtualMachines();
+        assertNotNull(machines);
+        assertTrue(machines.size() >= 0);
+    }
+
+    public void testReserveMachine()
+    {
+        assertFalse(env.machine.isReserved());
+
+        env.machine.reserveFor(env.enterprise);
+        assertTrue(env.machine.isReserved());
+
+        Enterprise owner = env.machine.getOwnerEnterprise();
+        assertNotNull(owner);
+        assertEquals(owner.getId(), env.enterprise.getId());
+    }
+
+    @Test(dependsOnMethods = "testReserveMachine")
+    public void testCancelReservation()
+    {
+        env.machine.cancelReservationFor(env.enterprise);
+        assertFalse(env.machine.isReserved());
+
+        Enterprise owner = env.machine.getOwnerEnterprise();
+        assertNull(owner);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/ManagedRackLiveUcsTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/ManagedRackLiveUcsTest.java
new file mode 100644
index 0000000..75ca5eb
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/ManagedRackLiveUcsTest.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.infrastructure.LogicServerPredicates;
+import org.jclouds.abiquo.predicates.infrastructure.ManagedRackPredicates;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.UcsRackDto;
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link ManagedRack} domain class.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "ucs", testName = "ManagedRackLiveUcsTest")
+public class ManagedRackLiveUcsTest extends BaseAbiquoApiLiveApiTest
+{
+    private LogicServer logicServer;
+
+    private Organization organization;
+
+    public void testUpdate()
+    {
+        env.ucsRack.setShortDescription("Updated description");
+        env.ucsRack.update();
+
+        // Recover the updated rack
+        UcsRackDto updated =
+            env.infrastructureApi.getManagedRack(env.datacenter.unwrap(), env.ucsRack.getId());
+
+        assertEquals(updated.getShortDescription(), "Updated description");
+    }
+
+    public void testListManagedRacks()
+    {
+        Iterable<ManagedRack> racks = env.datacenter.listManagedRacks();
+        assertEquals(Iterables.size(racks), 1);
+
+        racks = env.datacenter.listManagedRacks(ManagedRackPredicates.name(env.ucsRack.getName()));
+        assertEquals(Iterables.size(racks), 1);
+    }
+
+    public void testFindRack()
+    {
+        ManagedRack rack =
+            env.datacenter.findManagedRack(ManagedRackPredicates.name(env.ucsRack.getName()));
+        assertNotNull(rack);
+
+        rack =
+            env.datacenter.findManagedRack(ManagedRackPredicates.name(env.ucsRack.getName()
+                + "FAIL"));
+        assertNull(rack);
+    }
+
+    public void testCloneLogicServer()
+    {
+        List<LogicServer> originals = env.ucsRack.listServiceProfiles();
+        assertNotNull(originals);
+        assertTrue(originals.size() > 0);
+        LogicServer original = originals.get(0);
+
+        List<Organization> organizations = env.ucsRack.listOrganizations();
+        assertNotNull(organizations);
+        assertTrue(organizations.size() > 0);
+        organization = organizations.get(0);
+
+        env.ucsRack.cloneLogicServer(original, organization, "jclouds");
+
+        logicServer =
+            env.ucsRack.findServiceProfile(LogicServerPredicates.name(organization.getDn() + "/"
+                + "ls-jclouds"));
+        assertNotNull(logicServer);
+
+        String name = logicServer.getName();
+        assertEquals(name.substring(name.length() - 7, name.length()), "jclouds");
+    }
+
+    @Test(dependsOnMethods = "testCloneLogicServer")
+    public void testListFsms()
+    {
+        List<Fsm> fsms = env.ucsRack.listFsm(logicServer.getName());
+        assertNotNull(fsms);
+        assertTrue(fsms.size() > 0);
+    }
+
+    @Test(dependsOnMethods = {"testCloneLogicServer", "testListFsms"})
+    public void testDeleteLogicServer()
+    {
+        String name = logicServer.getName();
+
+        env.ucsRack.deleteLogicServer(logicServer);
+
+        LogicServer profile = env.ucsRack.findServiceProfile(LogicServerPredicates.name(name));
+        assertNull(profile);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/RackLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/RackLiveApiTest.java
new file mode 100644
index 0000000..0961998
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/RackLiveApiTest.java
@@ -0,0 +1,74 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.jclouds.abiquo.predicates.infrastructure.RackPredicates.name;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link Rack} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "RackLiveApiTest")
+public class RackLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testUpdate()
+    {
+        env.rack.setName("Updated rack");
+        env.rack.update();
+
+        // Recover the updated rack
+        RackDto updated = env.infrastructureApi.getRack(env.datacenter.unwrap(), env.rack.getId());
+
+        assertEquals(updated.getName(), "Updated rack");
+    }
+
+    public void testListRacks()
+    {
+        Iterable<Rack> racks = env.datacenter.listRacks();
+        assertEquals(Iterables.size(racks), 1);
+
+        racks = env.datacenter.listRacks(name(env.rack.getName()));
+        assertEquals(Iterables.size(racks), 1);
+
+        racks = env.datacenter.listRacks(name(env.rack.getName() + "FAIL"));
+        assertEquals(Iterables.size(racks), 0);
+    }
+
+    public void testFindRack()
+    {
+        Rack rack = env.datacenter.findRack(name(env.rack.getName()));
+        assertNotNull(rack);
+
+        rack = env.datacenter.findRack(name(env.rack.getName() + "FAIL"));
+        assertNull(rack);
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/RemoteServiceLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/RemoteServiceLiveApiTest.java
new file mode 100644
index 0000000..7cb1d1d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/RemoteServiceLiveApiTest.java
@@ -0,0 +1,131 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.jclouds.abiquo.predicates.infrastructure.RemoteServicePredicates.type;
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.net.URI;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.infrastructure.RemoteService.Builder;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.abiquo.server.core.infrastructure.RemoteServiceDto;
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link RemoteService} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "RemoteServiceLiveApiTest")
+public class RemoteServiceLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testUpdate()
+    {
+        // Update the remote service
+        RemoteService rs =
+            env.datacenter.findRemoteService(type(RemoteServiceType.VIRTUAL_FACTORY));
+        rs.setUri(rs.getUri());
+        rs.update();
+
+        // Recover the updated remote service
+        RemoteServiceDto updated =
+            env.infrastructureApi.getRemoteService(env.datacenter.unwrap(),
+                RemoteServiceType.VIRTUAL_FACTORY);
+
+        assertEquals(updated.getUri(), rs.getUri());
+    }
+
+    public void testDelete()
+    {
+        RemoteService rs = env.datacenter.findRemoteService(type(RemoteServiceType.BPM_SERVICE));
+        rs.delete();
+
+        // Recover the deleted remote service
+        RemoteServiceDto deleted =
+            env.infrastructureApi.getRemoteService(env.datacenter.unwrap(),
+                RemoteServiceType.BPM_SERVICE);
+
+        assertNull(deleted);
+
+        URI endpoint = URI.create(env.context.getApiContext().getProviderMetadata().getEndpoint());
+
+        // Restore rs
+        RemoteService bpm =
+            RemoteService.builder(env.context.getApiContext(), env.datacenter)
+                .type(RemoteServiceType.BPM_SERVICE).ip(endpoint.getHost()).build();
+        bpm.save();
+    }
+
+    public void testIsAvailableNonCheckeable()
+    {
+        RemoteService rs = env.datacenter.findRemoteService(type(RemoteServiceType.DHCP_SERVICE));
+        assertTrue(rs.isAvailable());
+    }
+
+    public void testIsAvailable()
+    {
+        RemoteService rs = env.datacenter.findRemoteService(type(RemoteServiceType.NODE_COLLECTOR));
+        assertTrue(rs.isAvailable());
+    }
+
+    public void testCreateRepeated()
+    {
+        RemoteService repeated = Builder.fromRemoteService(env.remoteServices.get(1)).build();
+
+        try
+        {
+            repeated.save();
+            fail("Should not be able to create duplicated remote services in the datacenter");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "RS-6");
+        }
+    }
+
+    public void testListRemoteServices()
+    {
+        Iterable<RemoteService> remoteServices = env.datacenter.listRemoteServices();
+        assertEquals(Iterables.size(remoteServices), env.remoteServices.size());
+
+        remoteServices = env.datacenter.listRemoteServices(type(RemoteServiceType.NODE_COLLECTOR));
+        assertEquals(Iterables.size(remoteServices), 1);
+    }
+
+    public void testFindRemoteService()
+    {
+        RemoteService remoteService =
+            env.datacenter.findRemoteService(type(RemoteServiceType.NODE_COLLECTOR));
+        assertNotNull(remoteService);
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/StorageDeviceLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/StorageDeviceLiveApiTest.java
new file mode 100644
index 0000000..4b3cf4c
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/StorageDeviceLiveApiTest.java
@@ -0,0 +1,85 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.infrastructure.StorageDevicePredicates;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceDto;
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link StorageDevice} domain class.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "StorageDeviceLiveApiTest")
+public class StorageDeviceLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testUpdate()
+    {
+        env.storageDevice.setName("Updated storage device");
+        env.storageDevice.update();
+
+        // Recover the updated storage device
+        StorageDeviceDto updated =
+            env.infrastructureApi.getStorageDevice(env.datacenter.unwrap(),
+                env.storageDevice.getId());
+
+        assertEquals(updated.getName(), "Updated storage device");
+    }
+
+    public void testListStorageDevices()
+    {
+        Iterable<StorageDevice> storageDevices = env.datacenter.listStorageDevices();
+        assertEquals(Iterables.size(storageDevices), 1);
+
+        storageDevices =
+            env.datacenter.listStorageDevices(StorageDevicePredicates.name(env.storageDevice
+                .getName()));
+        assertEquals(Iterables.size(storageDevices), 1);
+
+        storageDevices =
+            env.datacenter.listStorageDevices(StorageDevicePredicates.name(env.storageDevice
+                .getName() + "FAIL"));
+        assertEquals(Iterables.size(storageDevices), 0);
+    }
+
+    public void testFindStorageDevice()
+    {
+        StorageDevice storageDevice =
+            env.datacenter.findStorageDevice(StorageDevicePredicates.name(env.storageDevice
+                .getName()));
+        assertNotNull(storageDevice);
+
+        storageDevice =
+            env.datacenter.findStorageDevice(StorageDevicePredicates.name(env.storageDevice
+                .getName() + "FAIL"));
+        assertNull(storageDevice);
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/StoragePoolLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/StoragePoolLiveApiTest.java
new file mode 100644
index 0000000..4bfa795
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/StoragePoolLiveApiTest.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.infrastructure.StoragePoolPredicates;
+import org.jclouds.abiquo.predicates.infrastructure.TierPredicates;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link StorageDevice} domain class.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "StoragePoolLiveApiTest")
+public class StoragePoolLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testGetDevice()
+    {
+        StorageDevice device = env.storagePool.getStorageDevice();
+        assertNotNull(device);
+        assertEquals(device.getId(), env.storageDevice.getId());
+    }
+
+    public void testUpdate()
+    {
+        try
+        {
+            Tier tier3 = env.datacenter.findTier(TierPredicates.name("Default Tier 3"));
+            assertNotNull(tier3);
+            env.storagePool.setTier(tier3);
+            env.storagePool.update();
+
+            assertEquals(env.storagePool.getTier().getName(), "Default Tier 3");
+        }
+        finally
+        {
+            // Restore the original tier
+            env.storagePool.setTier(env.tier);
+            env.storagePool.update();
+            assertEquals(env.storagePool.getTier().getId(), env.tier.getId());
+        }
+    }
+
+    public void testListStoragePool()
+    {
+        Iterable<StoragePool> storagePools = env.storageDevice.listStoragePools();
+        assertEquals(Iterables.size(storagePools), 1);
+
+        storagePools =
+            env.storageDevice
+                .listStoragePools(StoragePoolPredicates.name(env.storagePool.getName()));
+        assertEquals(Iterables.size(storagePools), 1);
+
+        storagePools =
+            env.storageDevice.listStoragePools(StoragePoolPredicates.name(env.storagePool.getName()
+                + "FAIL"));
+        assertEquals(Iterables.size(storagePools), 0);
+    }
+
+    public void testFindStoragePool()
+    {
+        StoragePool storagePool =
+            env.storageDevice
+                .findStoragePool(StoragePoolPredicates.name(env.storagePool.getName()));
+        assertNotNull(storagePool);
+
+        storagePool =
+            env.storageDevice.findStoragePool(StoragePoolPredicates.name(env.storagePool.getName()
+                + "FAIL"));
+        assertNull(storagePool);
+    }
+
+    public void testRefreshStoragePool()
+    {
+        env.storagePool.refresh();
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/TierLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/TierLiveApiTest.java
new file mode 100644
index 0000000..1599452
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/infrastructure/TierLiveApiTest.java
@@ -0,0 +1,67 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.infrastructure.TierPredicates;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+
+/**
+ * Live integration tests for the {@link StorageDevice} domain class.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "TierLiveApiTest")
+public class TierLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+
+    public void testUpdate()
+    {
+        Tier tier = env.datacenter.listTiers().get(0);
+        assertNotNull(tier);
+
+        String previousName = tier.getName();
+        tier.setName("Updated tier");
+        tier.update();
+
+        // Recover the updated tier
+        Tier updated = env.datacenter.findTier(TierPredicates.name("Updated tier"));
+        assertEquals(updated.getName(), "Updated tier");
+
+        // Set original name
+        tier.setName(previousName);
+        tier.update();
+    }
+
+    public void testListTiers()
+    {
+        Iterable<Tier> tiers = env.datacenter.listTiers();
+        assertEquals(Iterables.size(tiers), 4);
+
+        tiers = env.datacenter.listTiers(TierPredicates.name("FAIL"));
+        assertEquals(Iterables.size(tiers), 0);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/ExternalNetworkLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/ExternalNetworkLiveApiTest.java
new file mode 100644
index 0000000..5c0c045
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/ExternalNetworkLiveApiTest.java
@@ -0,0 +1,186 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.network.IpPredicates;
+import org.jclouds.abiquo.predicates.network.NetworkPredicates;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.network.ExternalIpsDto;
+
+/**
+ * Live integration tests for the {@link ExternalNetwork} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ExternalNetworkLiveApiTest")
+public class ExternalNetworkLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private ExternalNetwork externalNetwork;
+
+    @BeforeClass
+    public void setupNetwork()
+    {
+        externalNetwork = createNetwork(env.externalNetwork, PREFIX + "-externalnetwork-test");
+    }
+
+    @AfterClass
+    public void tearDownNetwork()
+    {
+        externalNetwork.delete();
+    }
+
+    public void testListIps()
+    {
+        ExternalIpsDto ipsDto =
+            env.context.getApiContext().getApi().getInfrastructureApi()
+                .listExternalIps(externalNetwork.unwrap(), IpOptions.builder().limit(1).build());
+        int totalIps = ipsDto.getTotalSize();
+
+        List<ExternalIp> ips = externalNetwork.listIps();
+
+        assertEquals(ips.size(), totalIps);
+    }
+
+    public void testListIpsWithOptions()
+    {
+        List<ExternalIp> ips = externalNetwork.listIps(IpOptions.builder().limit(5).build());
+        assertEquals(ips.size(), 5);
+    }
+
+    public void testListUnusedIps()
+    {
+        ExternalIpsDto ipsDto =
+            env.context.getApiContext().getApi().getInfrastructureApi()
+                .listExternalIps(externalNetwork.unwrap(), IpOptions.builder().limit(1).build());
+        int totalIps = ipsDto.getTotalSize();
+
+        List<ExternalIp> ips = externalNetwork.listUnusedIps();
+        assertEquals(ips.size(), totalIps);
+    }
+
+    public void testUpdateBasicInfo()
+    {
+        externalNetwork.setName("External network Updated");
+        externalNetwork.setPrimaryDNS("8.8.8.8");
+        externalNetwork.setSecondaryDNS("8.8.8.8");
+        externalNetwork.update();
+
+        assertEquals(externalNetwork.getName(), "External network Updated");
+        assertEquals(externalNetwork.getPrimaryDNS(), "8.8.8.8");
+        assertEquals(externalNetwork.getSecondaryDNS(), "8.8.8.8");
+
+        // Refresh the external network
+        ExternalNetwork en =
+            env.enterprise.findExternalNetwork(env.datacenter,
+                NetworkPredicates.<ExternalIp> name(externalNetwork.getName()));
+
+        assertEquals(en.getId(), externalNetwork.getId());
+        assertEquals(en.getName(), "External network Updated");
+        assertEquals(en.getPrimaryDNS(), "8.8.8.8");
+        assertEquals(en.getSecondaryDNS(), "8.8.8.8");
+    }
+
+    public void testUpdateReadOnlyFields()
+    {
+        ExternalNetwork toUpdate = createNetwork(externalNetwork, PREFIX + "-exttoupdate-test");
+
+        try
+        {
+            toUpdate.setTag(20);
+            toUpdate.setAddress("10.1.0.0");
+            toUpdate.setMask(16);
+            toUpdate.update();
+
+            fail("Tag field should not be editable");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "VLAN-19");
+        }
+        finally
+        {
+            toUpdate.delete();
+        }
+    }
+
+    public void testUpdateWithInvalidValues()
+    {
+        ExternalNetwork toUpdate = createNetwork(externalNetwork, PREFIX + "-exttoupdate-test");
+
+        try
+        {
+            toUpdate.setMask(60);
+            toUpdate.update();
+
+            fail("Invalid mask value");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.BAD_REQUEST, "CONSTR-MAX");
+        }
+        finally
+        {
+            toUpdate.delete();
+        }
+    }
+
+    public void testGetEnterprise()
+    {
+        assertEquals(externalNetwork.getEnterprise().getId(), env.enterprise.getId());
+    }
+
+    public void testGetDatacenter()
+    {
+        assertEquals(externalNetwork.getDatacenter().getId(), env.datacenter.getId());
+    }
+
+    public void testGetNetworkFromIp()
+    {
+        ExternalIp ip = externalNetwork.findIp(IpPredicates.<ExternalIp> notUsed());
+        ExternalNetwork network = ip.getNetwork();
+
+        assertEquals(network.getId(), externalNetwork.getId());
+    }
+
+    private ExternalNetwork createNetwork(final ExternalNetwork from, final String name)
+    {
+        ExternalNetwork network = ExternalNetwork.Builder.fromExternalNetwork(from).build();
+        network.setName(name);
+        network.save();
+        assertNotNull(network.getId());
+        return network;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/GenericNetworkLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/GenericNetworkLiveApiTest.java
new file mode 100644
index 0000000..411af0f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/GenericNetworkLiveApiTest.java
@@ -0,0 +1,93 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.NetworkType;
+
+/**
+ * Live integration tests for the {@link Network} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "GenericNetworkLiveApiTest")
+public class GenericNetworkLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    public void testListDatacenterNetworks()
+    {
+        // Make sure all network types are listed
+        List<Network< ? >> networks = env.datacenter.listNetworks();
+        assertNotNull(networks);
+        assertEquals(networks.size(), 3);
+    }
+
+    public void testListPublicNetworks()
+    {
+        List<Network< ? >> networks = env.datacenter.listNetworks(NetworkType.PUBLIC);
+        assertNotNull(networks);
+        assertEquals(networks.size(), 1);
+
+        // Make sure it can be converted
+        networks.get(0).toPublicNetwork();
+    }
+
+    public void testListExternaletworks()
+    {
+        List<Network< ? >> networks = env.datacenter.listNetworks(NetworkType.EXTERNAL);
+        assertNotNull(networks);
+        assertEquals(networks.size(), 1);
+
+        // Make sure it can be converted
+        networks.get(0).toExternalNetwork();
+    }
+
+    public void testListUnmanagedNetworks()
+    {
+        List<Network< ? >> networks = env.datacenter.listNetworks(NetworkType.UNMANAGED);
+        assertNotNull(networks);
+        assertEquals(networks.size(), 1);
+
+        // Make sure it can be converted
+        networks.get(0).toUnmanagedNetwork();
+    }
+
+    public void testListPrivateNetworks()
+    {
+        try
+        {
+            env.datacenter.listNetworks(NetworkType.INTERNAL);
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.BAD_REQUEST, "QUERY-1");
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/PrivateNetworkLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/PrivateNetworkLiveApiTest.java
new file mode 100644
index 0000000..ca6bbff
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/PrivateNetworkLiveApiTest.java
@@ -0,0 +1,187 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.network.IpPredicates;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.network.PrivateIpsDto;
+
+/**
+ * Live integration tests for the {@link PrivateNetwork} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "PrivateNetworkLiveApiTest")
+public class PrivateNetworkLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private PrivateNetwork privateNetwork;
+
+    @BeforeClass
+    public void setupNetwork()
+    {
+        privateNetwork =
+            createNetwork(env.virtualDatacenter, env.privateNetwork, PREFIX
+                + "-privatenetwork-test");
+    }
+
+    @AfterClass
+    public void tearDownNetwork()
+    {
+        privateNetwork.delete();
+    }
+
+    public void testListIps()
+    {
+        PrivateIpsDto ipsDto =
+            env.context
+                .getApiContext()
+                .getApi()
+                .getCloudApi()
+                .listPrivateNetworkIps(privateNetwork.unwrap(),
+                    IpOptions.builder().limit(1).build());
+        int totalIps = ipsDto.getTotalSize();
+
+        List<PrivateIp> ips = privateNetwork.listIps();
+
+        assertEquals(ips.size(), totalIps);
+    }
+
+    public void testListIpsWithOptions()
+    {
+        List<PrivateIp> ips = privateNetwork.listIps(IpOptions.builder().limit(5).build());
+        assertEquals(ips.size(), 5);
+    }
+
+    public void testListUnusedIps()
+    {
+        PrivateIpsDto ipsDto =
+            env.context
+                .getApiContext()
+                .getApi()
+                .getCloudApi()
+                .listPrivateNetworkIps(privateNetwork.unwrap(),
+                    IpOptions.builder().limit(1).build());
+        int totalIps = ipsDto.getTotalSize();
+
+        List<PrivateIp> ips = privateNetwork.listUnusedIps();
+        assertEquals(ips.size(), totalIps);
+    }
+
+    public void testUpdateBasicInfo()
+    {
+        privateNetwork.setName("Private network Updated");
+        privateNetwork.setPrimaryDNS("8.8.8.8");
+        privateNetwork.setSecondaryDNS("8.8.8.8");
+        privateNetwork.update();
+
+        assertEquals(privateNetwork.getName(), "Private network Updated");
+        assertEquals(privateNetwork.getPrimaryDNS(), "8.8.8.8");
+        assertEquals(privateNetwork.getSecondaryDNS(), "8.8.8.8");
+
+        // Refresh the private network
+        PrivateNetwork pn = env.virtualDatacenter.getPrivateNetwork(privateNetwork.getId());
+
+        assertEquals(pn.getName(), "Private network Updated");
+        assertEquals(pn.getPrimaryDNS(), "8.8.8.8");
+        assertEquals(pn.getSecondaryDNS(), "8.8.8.8");
+    }
+
+    public void testUpdateReadOnlyFields()
+    {
+        PrivateNetwork toUpdate =
+            createNetwork(env.virtualDatacenter, privateNetwork, PREFIX + "-privtoupdate-test");
+
+        try
+        {
+            toUpdate.setTag(20);
+            toUpdate.setAddress("10.1.1.0");
+            toUpdate.setMask(16);
+            toUpdate.update();
+
+            fail("Tag field should not be editable");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "VLAN-10");
+        }
+        finally
+        {
+            toUpdate.delete();
+        }
+    }
+
+    public void testUpdateWithInvalidValues()
+    {
+        PrivateNetwork toUpdate =
+            createNetwork(env.virtualDatacenter, privateNetwork, PREFIX + "-privtoupdate-test");
+
+        try
+        {
+            toUpdate.setMask(60);
+            toUpdate.update();
+
+            fail("Invalid mask value");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.BAD_REQUEST, "CONSTR-MAX");
+        }
+        finally
+        {
+            toUpdate.delete();
+        }
+    }
+
+    public void testGetNetworkFromIp()
+    {
+        PrivateIp ip = privateNetwork.findIp(IpPredicates.<PrivateIp> notUsed());
+        PrivateNetwork network = ip.getNetwork();
+
+        assertEquals(network.getId(), privateNetwork.getId());
+    }
+
+    private PrivateNetwork createNetwork(final VirtualDatacenter vdc, final PrivateNetwork from,
+        final String name)
+    {
+        PrivateNetwork network =
+            PrivateNetwork.Builder.fromPrivateNetwork(from).virtualDatacenter(vdc).build();
+        network.setName(name);
+        network.save();
+        assertNotNull(network.getId());
+        return network;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/PublicNetworkLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/PublicNetworkLiveApiTest.java
new file mode 100644
index 0000000..4456a1b
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/PublicNetworkLiveApiTest.java
@@ -0,0 +1,178 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.network.IpPredicates;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+
+/**
+ * Live integration tests for the {@link PublicNetwork} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "PublicNetworkLiveApiTest")
+public class PublicNetworkLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private PublicNetwork publicNetwork;
+
+    @BeforeClass
+    public void setupNetwork()
+    {
+        publicNetwork = createNetwork(env.publicNetwork, PREFIX + "-publicnetwork-test");
+    }
+
+    @AfterClass
+    public void tearDownNetwork()
+    {
+        publicNetwork.delete();
+    }
+
+    public void testListIps()
+    {
+        PublicIpsDto ipsDto =
+            env.context.getApiContext().getApi().getInfrastructureApi()
+                .listPublicIps(publicNetwork.unwrap(), IpOptions.builder().limit(1).build());
+        int totalIps = ipsDto.getTotalSize();
+
+        List<PublicIp> ips = publicNetwork.listIps();
+
+        assertEquals(ips.size(), totalIps);
+    }
+
+    public void testListIpsWithOptions()
+    {
+        List<PublicIp> ips = publicNetwork.listIps(IpOptions.builder().limit(5).build());
+        assertEquals(ips.size(), 5);
+    }
+
+    public void testListUnusedIps()
+    {
+        PublicIpsDto ipsDto =
+            env.context.getApiContext().getApi().getInfrastructureApi()
+                .listPublicIps(publicNetwork.unwrap(), IpOptions.builder().limit(1).build());
+        int totalIps = ipsDto.getTotalSize();
+
+        List<PublicIp> ips = publicNetwork.listUnusedIps();
+        assertEquals(ips.size(), totalIps);
+    }
+
+    public void testUpdateBasicInfo()
+    {
+        publicNetwork.setName("Public network Updated");
+        publicNetwork.setPrimaryDNS("8.8.8.8");
+        publicNetwork.setSecondaryDNS("8.8.8.8");
+        publicNetwork.update();
+
+        assertEquals(publicNetwork.getName(), "Public network Updated");
+        assertEquals(publicNetwork.getPrimaryDNS(), "8.8.8.8");
+        assertEquals(publicNetwork.getSecondaryDNS(), "8.8.8.8");
+
+        // Refresh the public network
+        PublicNetwork pn = env.datacenter.getNetwork(publicNetwork.getId()).toPublicNetwork();
+
+        assertEquals(pn.getId(), publicNetwork.getId());
+        assertEquals(pn.getName(), "Public network Updated");
+        assertEquals(pn.getPrimaryDNS(), "8.8.8.8");
+        assertEquals(pn.getSecondaryDNS(), "8.8.8.8");
+    }
+
+    public void testUpdateReadOnlyFields()
+    {
+        PublicNetwork toUpdate = createNetwork(publicNetwork, PREFIX + "-pubtoupdate-test");
+
+        try
+        {
+            toUpdate.setTag(20);
+            toUpdate.setAddress("80.81.81.0");
+            toUpdate.setMask(16);
+            toUpdate.update();
+
+            fail("Tag field should not be editable");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "VLAN-19");
+        }
+        finally
+        {
+            toUpdate.delete();
+        }
+    }
+
+    public void testUpdateWithInvalidValues()
+    {
+        PublicNetwork toUpdate = createNetwork(publicNetwork, PREFIX + "-pubtoupdate-test");
+
+        try
+        {
+            toUpdate.setMask(60);
+            toUpdate.update();
+
+            fail("Invalid mask value");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.BAD_REQUEST, "CONSTR-MAX");
+        }
+        finally
+        {
+            toUpdate.delete();
+        }
+    }
+
+    public void testGetDatacenter()
+    {
+        assertEquals(publicNetwork.getDatacenter().getId(), env.datacenter.getId());
+    }
+
+    public void testGetNetworkFromIp()
+    {
+        PublicIp ip = publicNetwork.findIp(IpPredicates.<PublicIp> notUsed());
+        PublicNetwork network = ip.getNetwork();
+
+        assertEquals(network.getId(), publicNetwork.getId());
+    }
+
+    private PublicNetwork createNetwork(final PublicNetwork from, final String name)
+    {
+        PublicNetwork network = PublicNetwork.Builder.fromPublicNetwork(from).build();
+        network.setName(name);
+        network.save();
+        assertNotNull(network.getId());
+        return network;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/UnmanagedNetworkLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/UnmanagedNetworkLiveApiTest.java
new file mode 100644
index 0000000..596e54d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/domain/network/UnmanagedNetworkLiveApiTest.java
@@ -0,0 +1,187 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.domain.network;
+
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.jclouds.abiquo.util.Assert.assertHasError;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.jclouds.abiquo.predicates.network.IpPredicates;
+import org.jclouds.abiquo.predicates.network.NetworkPredicates;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpsDto;
+
+/**
+ * Live integration tests for the {@link UnmanagedNetwork} domain class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "UnmanagedNetworkLiveApiTest")
+public class UnmanagedNetworkLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    private UnmanagedNetwork unmanagedNetwork;
+
+    @BeforeClass
+    public void setupNetwork()
+    {
+        unmanagedNetwork = createNetwork(env.unmanagedNetwork, PREFIX + "-unmanagednetwork-test");
+    }
+
+    @AfterClass
+    public void tearDownNetwork()
+    {
+        unmanagedNetwork.delete();
+    }
+
+    public void testListIps()
+    {
+        UnmanagedIpsDto ipsDto =
+            env.context.getApiContext().getApi().getInfrastructureApi()
+                .listUnmanagedIps(unmanagedNetwork.unwrap(), IpOptions.builder().limit(1).build());
+        int totalIps = ipsDto.getTotalSize();
+
+        List<UnmanagedIp> ips = unmanagedNetwork.listIps();
+
+        assertEquals(ips.size(), totalIps);
+    }
+
+    public void testListIpsWithOptions()
+    {
+        List<UnmanagedIp> ips = unmanagedNetwork.listIps(IpOptions.builder().limit(5).build());
+        // Unmanaged networks do not have IPs until attached to VMs
+        assertEquals(ips.size(), 0);
+    }
+
+    public void testListUnusedIps()
+    {
+        UnmanagedIpsDto ipsDto =
+            env.context.getApiContext().getApi().getInfrastructureApi()
+                .listUnmanagedIps(unmanagedNetwork.unwrap(), IpOptions.builder().limit(1).build());
+        int totalIps = ipsDto.getTotalSize();
+
+        List<UnmanagedIp> ips = unmanagedNetwork.listUnusedIps();
+        assertEquals(ips.size(), totalIps);
+    }
+
+    public void testUpdateBasicInfo()
+    {
+        unmanagedNetwork.setName("Unmanaged network Updated");
+        unmanagedNetwork.setPrimaryDNS("8.8.8.8");
+        unmanagedNetwork.setSecondaryDNS("8.8.8.8");
+        unmanagedNetwork.update();
+
+        assertEquals(unmanagedNetwork.getName(), "Unmanaged network Updated");
+        assertEquals(unmanagedNetwork.getPrimaryDNS(), "8.8.8.8");
+        assertEquals(unmanagedNetwork.getSecondaryDNS(), "8.8.8.8");
+
+        // Refresh the unmanaged network
+        UnmanagedNetwork en =
+            env.enterprise.findUnmanagedNetwork(env.datacenter,
+                NetworkPredicates.<UnmanagedIp> name(unmanagedNetwork.getName()));
+
+        assertEquals(en.getId(), unmanagedNetwork.getId());
+        assertEquals(en.getName(), "Unmanaged network Updated");
+        assertEquals(en.getPrimaryDNS(), "8.8.8.8");
+        assertEquals(en.getSecondaryDNS(), "8.8.8.8");
+    }
+
+    public void testUpdateReadOnlyFields()
+    {
+        UnmanagedNetwork toUpdate = createNetwork(unmanagedNetwork, PREFIX + "-umtoupdate-test");
+
+        try
+        {
+            toUpdate.setTag(20);
+            toUpdate.setAddress("10.2.0.0");
+            toUpdate.setMask(16);
+            toUpdate.update();
+
+            fail("Tag field should not be editable");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.CONFLICT, "VLAN-19");
+        }
+        finally
+        {
+            toUpdate.delete();
+        }
+    }
+
+    public void testUpdateWithInvalidValues()
+    {
+        UnmanagedNetwork toUpdate = createNetwork(unmanagedNetwork, PREFIX + "-umtoupdate-test");
+
+        try
+        {
+            toUpdate.setMask(60);
+            toUpdate.update();
+
+            fail("Invalid mask value");
+        }
+        catch (AbiquoException ex)
+        {
+            assertHasError(ex, Status.BAD_REQUEST, "CONSTR-MAX");
+        }
+        finally
+        {
+            toUpdate.delete();
+        }
+    }
+
+    public void testGetEnterprise()
+    {
+        assertEquals(unmanagedNetwork.getEnterprise().getId(), env.enterprise.getId());
+    }
+
+    public void testGetDatacenter()
+    {
+        assertEquals(unmanagedNetwork.getDatacenter().getId(), env.datacenter.getId());
+    }
+
+    public void testGetNetworkFromIp()
+    {
+        UnmanagedIp ip = unmanagedNetwork.findIp(IpPredicates.<UnmanagedIp> notUsed());
+        // Unmanaged networks do not have IPs until attached to VMs
+        assertNull(ip);
+    }
+
+    private UnmanagedNetwork createNetwork(final UnmanagedNetwork from, final String name)
+    {
+        UnmanagedNetwork network = UnmanagedNetwork.Builder.fromUnmanagedNetwork(from).build();
+        network.setName(name);
+        network.save();
+        assertNotNull(network.getId());
+        return network;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/CloudTestEnvironment.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/CloudTestEnvironment.java
new file mode 100644
index 0000000..263f4ae
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/CloudTestEnvironment.java
@@ -0,0 +1,250 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.environment;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.jclouds.ContextBuilder;
+import org.jclouds.abiquo.AbiquoApiMetadata;
+import org.jclouds.abiquo.AbiquoContext;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PrivateNetwork;
+import org.jclouds.abiquo.features.CloudApi;
+import org.jclouds.abiquo.features.services.EventService;
+import org.jclouds.abiquo.predicates.enterprise.EnterprisePredicates;
+import org.jclouds.abiquo.predicates.network.NetworkPredicates;
+
+import com.google.common.collect.Ordering;
+import com.google.common.primitives.Longs;
+
+/**
+ * Test environment for cloud live tests.
+ * 
+ * @author Francesc Montserrat
+ */
+public class CloudTestEnvironment extends InfrastructureTestEnvironment
+{
+
+    // Environment data made public so tests can use them easily
+    public CloudApi cloudApi;
+
+    public EventService eventService;
+
+    public VirtualDatacenter virtualDatacenter;
+
+    public VirtualAppliance virtualAppliance;
+
+    public VirtualMachine virtualMachine;
+
+    public VirtualMachineTemplate template;
+
+    public PrivateNetwork privateNetwork;
+
+    public Enterprise defaultEnterprise;
+
+    public AbiquoContext plainUserContext;
+
+    public AbiquoContext enterpriseAdminContext;
+
+    public CloudTestEnvironment(final AbiquoContext context)
+    {
+        super(context);
+        this.cloudApi = context.getApiContext().getApi().getCloudApi();
+        this.eventService = context.getEventService();
+    }
+
+    @Override
+    public void setup() throws Exception
+    {
+        // Create base infrastructure
+        super.setup();
+
+        createUserContext();
+        createEnterpriseAdminContext();
+
+        findDefaultEnterprise();
+        createVirtualDatacenter();
+        createVirtualAppliance();
+        refreshTemplateRepository();
+        createVirtualMachine();
+    }
+
+    @Override
+    public void tearDown() throws Exception
+    {
+        closeEnterpriseAdminContext();
+        closeUserContext();
+
+        deleteVirtualMachine();
+        deleteVirtualAppliance();
+        deleteVirtualDatacenter();
+
+        // Delete base infrastructure
+        super.tearDown();
+    }
+
+    // Setup
+
+    private void createUserContext()
+    {
+        String endpoint =
+            checkNotNull(System.getProperty("test.abiquo.endpoint"), "test.abiquo.endpoint");
+
+        plainUserContext = ContextBuilder.newBuilder(new AbiquoApiMetadata()) //
+            .endpoint(endpoint) //
+            .credentials("abiquo", "jclouds") //
+            .build(AbiquoContext.class);
+    }
+
+    private void createEnterpriseAdminContext()
+    {
+        String endpoint =
+            checkNotNull(System.getProperty("test.abiquo.endpoint"), "test.abiquo.endpoint");
+
+        enterpriseAdminContext = ContextBuilder.newBuilder(new AbiquoApiMetadata()) //
+            .endpoint(endpoint) //
+            .credentials("jclouds-admin", "admin") //
+            .build(AbiquoContext.class);
+    }
+
+    protected void findDefaultEnterprise()
+    {
+        defaultEnterprise =
+            context.getAdministrationService().findEnterprise(EnterprisePredicates.name("Abiquo"));
+    }
+
+    protected void createVirtualDatacenter()
+    {
+        privateNetwork =
+            PrivateNetwork.builder(context.getApiContext()).name("DefaultNetwork")
+                .gateway("192.168.1.1").address("192.168.1.0").mask(24).build();
+
+        virtualDatacenter =
+            VirtualDatacenter.builder(context.getApiContext(), datacenter, defaultEnterprise)
+                .name(PREFIX + "Virtual Aloha").cpuCountLimits(18, 20)
+                .hdLimitsInMb(279172872, 279172872).publicIpsLimits(2, 3).ramLimits(19456, 20480)
+                .storageLimits(289910292, 322122547).vlansLimits(3, 4)
+                .hypervisorType(machine.getType()).network(privateNetwork).build();
+
+        virtualDatacenter.save();
+        assertNotNull(virtualDatacenter.getId());
+
+        privateNetwork =
+            virtualDatacenter.findPrivateNetwork(NetworkPredicates.<PrivateIp> name(privateNetwork
+                .getName()));
+    }
+
+    protected void createVirtualAppliance()
+    {
+        virtualAppliance =
+            VirtualAppliance.builder(context.getApiContext(), virtualDatacenter)
+                .name(PREFIX + "Virtual AppAloha").build();
+
+        virtualAppliance.save();
+        assertNotNull(virtualAppliance.getId());
+    }
+
+    protected void createVirtualMachine()
+    {
+        List<VirtualMachineTemplate> templates = virtualDatacenter.listAvailableTemplates();
+        assertFalse(templates.isEmpty());
+
+        // Sort by size to use the smallest one
+        Collections.sort(templates, new Ordering<VirtualMachineTemplate>()
+        {
+            @Override
+            public int compare(final VirtualMachineTemplate left, final VirtualMachineTemplate right)
+            {
+                return Longs.compare(left.getDiskFileSize(), right.getDiskFileSize());
+            }
+        });
+
+        template = templates.get(0);
+
+        virtualMachine =
+            VirtualMachine.builder(context.getApiContext(), virtualAppliance, template).cpu(2)
+                .nameLabel(PREFIX + "VM Aloha").ram(128).build();
+
+        virtualMachine.save();
+        assertNotNull(virtualMachine.getId());
+
+    }
+
+    protected void refreshTemplateRepository()
+    {
+        defaultEnterprise.refreshTemplateRepository(datacenter);
+    }
+
+    // Tear down
+
+    private void closeUserContext()
+    {
+        plainUserContext.close();
+    }
+
+    private void closeEnterpriseAdminContext()
+    {
+        enterpriseAdminContext.close();
+    }
+
+    protected void deleteVirtualDatacenter()
+    {
+        if (virtualDatacenter != null && enterprise != null && datacenter != null)
+        {
+            Integer idVirtualDatacenter = virtualDatacenter.getId();
+            virtualDatacenter.delete();
+            assertNull(cloudApi.getVirtualDatacenter(idVirtualDatacenter));
+        }
+    }
+
+    protected void deleteVirtualAppliance()
+    {
+        if (virtualAppliance != null && virtualDatacenter != null)
+        {
+            Integer idVirtualAppliance = virtualAppliance.getId();
+            virtualAppliance.delete();
+            assertNull(cloudApi.getVirtualAppliance(virtualDatacenter.unwrap(), idVirtualAppliance));
+        }
+    }
+
+    protected void deleteVirtualMachine()
+    {
+        if (virtualMachine != null && virtualAppliance != null && virtualDatacenter != null)
+        {
+            Integer idVirtualMachine = virtualMachine.getId();
+            virtualMachine.delete();
+            assertNull(cloudApi.getVirtualMachine(virtualAppliance.unwrap(), idVirtualMachine));
+        }
+
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/InfrastructureTestEnvironment.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/InfrastructureTestEnvironment.java
new file mode 100644
index 0000000..17d9db6
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/InfrastructureTestEnvironment.java
@@ -0,0 +1,531 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.environment;
+
+import static com.google.common.collect.Iterables.find;
+import static org.jclouds.abiquo.reference.AbiquoTestConstants.PREFIX;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.UUID;
+
+import org.jclouds.abiquo.AbiquoContext;
+import org.jclouds.abiquo.config.AbiquoEdition;
+import org.jclouds.abiquo.domain.config.License;
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.domain.enterprise.Limits;
+import org.jclouds.abiquo.domain.enterprise.Role;
+import org.jclouds.abiquo.domain.enterprise.User;
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.infrastructure.Datastore;
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+import org.jclouds.abiquo.domain.infrastructure.ManagedRack;
+import org.jclouds.abiquo.domain.infrastructure.Rack;
+import org.jclouds.abiquo.domain.infrastructure.RemoteService;
+import org.jclouds.abiquo.domain.infrastructure.StorageDevice;
+import org.jclouds.abiquo.domain.infrastructure.StorageDeviceMetadata;
+import org.jclouds.abiquo.domain.infrastructure.StoragePool;
+import org.jclouds.abiquo.domain.infrastructure.Tier;
+import org.jclouds.abiquo.domain.network.ExternalNetwork;
+import org.jclouds.abiquo.domain.network.PublicNetwork;
+import org.jclouds.abiquo.domain.network.UnmanagedNetwork;
+import org.jclouds.abiquo.features.AdminApi;
+import org.jclouds.abiquo.features.ConfigApi;
+import org.jclouds.abiquo.features.EnterpriseApi;
+import org.jclouds.abiquo.features.InfrastructureApi;
+import org.jclouds.abiquo.features.services.AdministrationService;
+import org.jclouds.abiquo.predicates.enterprise.RolePredicates;
+import org.jclouds.abiquo.predicates.enterprise.UserPredicates;
+import org.jclouds.abiquo.predicates.infrastructure.RemoteServicePredicates;
+import org.jclouds.abiquo.predicates.infrastructure.StorageDeviceMetadataPredicates;
+import org.jclouds.abiquo.predicates.infrastructure.StoragePoolPredicates;
+import org.jclouds.abiquo.predicates.infrastructure.TierPredicates;
+import org.jclouds.abiquo.util.Config;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Resources;
+
+/**
+ * Test environment for infrastructure live tests.
+ * 
+ * @author Ignasi Barrera
+ */
+public class InfrastructureTestEnvironment implements TestEnvironment
+{
+    /** The rest context. */
+    public AbiquoContext context;
+
+    // Environment data made public so tests can use them easily
+
+    public AdministrationService administrationService;
+
+    public InfrastructureApi infrastructureApi;
+
+    public EnterpriseApi enterpriseApi;
+
+    public AdminApi adminApi;
+
+    public ConfigApi configApi;
+
+    // Resources
+
+    public License license;
+
+    public Datacenter datacenter;
+
+    public PublicNetwork publicNetwork;
+
+    public ExternalNetwork externalNetwork;
+
+    public UnmanagedNetwork unmanagedNetwork;
+
+    public List<RemoteService> remoteServices;
+
+    public Rack rack;
+
+    public Machine machine;
+
+    public Enterprise enterprise;
+
+    public StorageDevice storageDevice;
+
+    public StoragePool storagePool;
+
+    public Tier tier;
+
+    public User user;
+
+    public User enterpriseAdmin;
+
+    public Role role;
+
+    public Role anotherRole;
+
+    public ManagedRack ucsRack;
+
+    public InfrastructureTestEnvironment(final AbiquoContext context)
+    {
+        super();
+        this.context = context;
+        this.administrationService = context.getAdministrationService();
+        this.context = context;
+        this.enterpriseApi = context.getApiContext().getApi().getEnterpriseApi();
+        this.infrastructureApi = context.getApiContext().getApi().getInfrastructureApi();
+        this.adminApi = context.getApiContext().getApi().getAdminApi();
+        this.configApi = context.getApiContext().getApi().getConfigApi();
+    }
+
+    @Override
+    public void setup() throws Exception
+    {
+        // Configuration
+        createLicense();
+
+        // Intrastructure
+        createDatacenter();
+        createRack();
+        createMachine();
+        createStorageDevice();
+        createStoragePool();
+        createPublicNetwork();
+
+        // Enterprise
+        createEnterprise();
+        createRoles();
+        createUsers();
+
+        // Networking
+        createExternalNetwork();
+        createUnmanagedNetwork();
+    }
+
+    @Override
+    public void tearDown() throws Exception
+    {
+        deleteUsers();
+
+        deleteRole(role);
+        deleteRole(anotherRole);
+
+        deleteUnmanagedNetwork();
+        deleteExternalNetwork();
+        deletePublicNetwork();
+        deleteStoragePool();
+        deleteStorageDevice();
+        deleteMachine();
+        deleteUcsRack();
+        deleteRack();
+        deleteDatacenter();
+        deleteEnterprise();
+
+        deleteLicense();
+    }
+
+    // Setup
+
+    protected void createLicense() throws IOException
+    {
+        license = License.builder(context.getApiContext(), readLicense()).build();
+
+        license.add();
+        assertNotNull(license.getId());
+    }
+
+    protected void createDatacenter()
+    {
+        // Assume a monolithic install
+        URI endpoint = URI.create(context.getApiContext().getProviderMetadata().getEndpoint());
+        String remoteServicesAddress = endpoint.getHost();
+
+        datacenter =
+            Datacenter.builder(context.getApiContext()).name(randomName()).location("Honolulu")
+                .remoteServices(remoteServicesAddress, AbiquoEdition.ENTERPRISE).build();
+        datacenter.save();
+        assertNotNull(datacenter.getId());
+
+        remoteServices = datacenter.listRemoteServices();
+        assertEquals(remoteServices.size(), 7);
+    }
+
+    protected void createMachine()
+    {
+        String ip = Config.get("abiquo.hypervisor.address");
+        HypervisorType type = HypervisorType.valueOf(Config.get("abiquo.hypervisor.type"));
+        String user = Config.get("abiquo.hypervisor.user");
+        String pass = Config.get("abiquo.hypervisor.pass");
+
+        machine = datacenter.discoverSingleMachine(ip, type, user, pass);
+
+        String vswitch =
+            machine.findAvailableVirtualSwitch(Config.get("abiquo.hypervisor.vswitch"));
+        machine.setVirtualSwitch(vswitch);
+
+        Datastore datastore = machine.findDatastore(Config.get("abiquo.hypervisor.datastore"));
+        datastore.setEnabled(true);
+
+        machine.setRack(rack);
+        machine.save();
+        assertNotNull(machine.getId());
+    }
+
+    protected void createRack()
+    {
+        rack = Rack.builder(context.getApiContext(), datacenter).name(PREFIX + "Aloha").build();
+        rack.save();
+        assertNotNull(rack.getId());
+    }
+
+    public void createUcsRack()
+    {
+        String ip = Config.get("abiquo.ucs.address");
+        Integer port = Integer.parseInt(Config.get("abiquo.ucs.port"));
+        String user = Config.get("abiquo.ucs.user");
+        String pass = Config.get("abiquo.ucs.pass");
+
+        ucsRack =
+            ManagedRack.builder(context.getApiContext(), datacenter).ipAddress(ip).port(port)
+                .user(user).name("ucs rack").password(pass).build();
+
+        ucsRack.save();
+        assertNotNull(ucsRack.getId());
+    }
+
+    protected void createStorageDevice()
+    {
+        String ip = Config.get("abiquo.storage.address");
+        String type = Config.get("abiquo.storage.type");
+        String user = Config.get("abiquo.storage.user");
+        String pass = Config.get("abiquo.storage.pass");
+
+        List<StorageDeviceMetadata> devices = datacenter.listSupportedStorageDevices();
+        StorageDeviceMetadata metadata =
+            Iterables.find(devices, StorageDeviceMetadataPredicates.type(type));
+
+        storageDevice = StorageDevice.builder(context.getApiContext(), datacenter) //
+            .name(PREFIX + "Storage Device")//
+            .type(type)//
+            .managementIp(ip).managementPort(metadata.getDefaultManagementPort())//
+            .iscsiIp(ip).iscsiPort(metadata.getDefaultIscsiPort()) //
+            .username(user)//
+            .password(pass) //
+            .build();
+
+        storageDevice.save();
+        assertNotNull(storageDevice.getId());
+    }
+
+    protected void createStoragePool()
+    {
+        String pool = Config.get("abiquo.storage.pool");
+
+        storagePool = storageDevice.findRemoteStoragePool(StoragePoolPredicates.name(pool));
+        tier = datacenter.findTier(TierPredicates.name("Default Tier 1"));
+
+        storagePool.setTier(tier);
+        storagePool.save();
+
+        assertNotNull(storagePool.getUUID());
+    }
+
+    protected void createUsers()
+    {
+        Role userRole = administrationService.findRole(RolePredicates.name("USER"));
+        Role enterpriseAdminRole =
+            administrationService.findRole(RolePredicates.name("ENTERPRISE_ADMIN"));
+
+        user =
+            User.builder(context.getApiContext(), enterprise, userRole)
+                .name(randomName(), randomName()).nick("jclouds").authType("ABIQUO")
+                .description(randomName()).email(randomName() + "@abiquo.com").locale("en_US")
+                .password("user").build();
+
+        user.save();
+        assertNotNull(user.getId());
+        assertEquals(userRole.getId(), user.getRole().getId());
+
+        enterpriseAdmin =
+            User.builder(context.getApiContext(), enterprise, enterpriseAdminRole)
+                .name(randomName(), randomName()).nick("jclouds-admin").authType("ABIQUO")
+                .description(randomName()).email(randomName() + "@abiquo.com").locale("en_US")
+                .password("admin").build();
+
+        enterpriseAdmin.save();
+        assertNotNull(enterpriseAdmin.getId());
+        assertEquals(enterpriseAdminRole.getId(), enterpriseAdmin.getRole().getId());
+    }
+
+    protected void createRoles()
+    {
+        role = Role.builder(context.getApiContext()).name(randomName()).blocked(false).build();
+        role.save();
+
+        anotherRole = Role.Builder.fromRole(role).build();
+        anotherRole.setName("Another role");
+        anotherRole.save();
+
+        assertNotNull(role.getId());
+        assertNotNull(anotherRole.getId());
+    }
+
+    protected void createEnterprise()
+    {
+        enterprise = Enterprise.builder(context.getApiContext()).name(randomName()).build();
+        enterprise.save();
+        assertNotNull(enterprise.getId());
+        Limits limits = enterprise.allowDatacenter(datacenter);
+        assertNotNull(limits);
+    }
+
+    protected void createPublicNetwork()
+    {
+        publicNetwork =
+            PublicNetwork.builder(context.getApiContext(), datacenter).name("PublicNetwork")
+                .gateway("80.80.80.1").address("80.80.80.0").mask(24).tag(5).build();
+        publicNetwork.save();
+        assertNotNull(publicNetwork.getId());
+    }
+
+    protected void createExternalNetwork()
+    {
+        externalNetwork =
+            ExternalNetwork.builder(context.getApiContext(), datacenter, enterprise)
+                .name("ExternalNetwork").gateway("10.0.0.1").address("10.0.0.0").mask(24).tag(7)
+                .build();
+        externalNetwork.save();
+        assertNotNull(externalNetwork.getId());
+    }
+
+    protected void createUnmanagedNetwork()
+    {
+        unmanagedNetwork =
+            UnmanagedNetwork.builder(context.getApiContext(), datacenter, enterprise)
+                .name("UnmanagedNetwork").gateway("10.0.1.1").address("10.0.1.0").mask(24).tag(8)
+                .build();
+        unmanagedNetwork.save();
+        assertNotNull(unmanagedNetwork.getId());
+    }
+
+    // Tear down
+
+    protected void deleteUnmanagedNetwork()
+    {
+        if (unmanagedNetwork != null)
+        {
+            Integer id = unmanagedNetwork.getId();
+            unmanagedNetwork.delete();
+            assertNull(datacenter.getNetwork(id));
+        }
+    }
+
+    protected void deleteExternalNetwork()
+    {
+        if (externalNetwork != null)
+        {
+            Integer id = externalNetwork.getId();
+            externalNetwork.delete();
+            assertNull(datacenter.getNetwork(id));
+        }
+    }
+
+    protected void deletePublicNetwork()
+    {
+        if (publicNetwork != null)
+        {
+            Integer id = publicNetwork.getId();
+            publicNetwork.delete();
+            assertNull(datacenter.getNetwork(id));
+        }
+    }
+
+    protected void deleteUsers()
+    {
+        if (user != null)
+        {
+            String nick = user.getNick();
+            user.delete();
+            // Nick is unique in an enterprise
+            assertNull(enterprise.findUser(UserPredicates.nick(nick)));
+        }
+
+        if (enterpriseAdmin != null)
+        {
+            String nick = enterpriseAdmin.getNick();
+            enterpriseAdmin.delete();
+            // Nick is unique in an enterprise
+            assertNull(enterprise.findUser(UserPredicates.nick(nick)));
+        }
+    }
+
+    protected void deleteRole(final Role role)
+    {
+        if (role != null)
+        {
+            Integer roleId = role.getId();
+            role.delete();
+            assertNull(adminApi.getRole(roleId));
+        }
+    }
+
+    protected void deleteStoragePool()
+    {
+        if (storagePool != null)
+        {
+            String idStoragePool = storagePool.getUUID();
+            storagePool.delete();
+            assertNull(infrastructureApi.getStoragePool(storageDevice.unwrap(), idStoragePool));
+        }
+
+    }
+
+    protected void deleteStorageDevice()
+    {
+        if (storageDevice != null)
+        {
+            Integer idStorageDevice = storageDevice.getId();
+            storageDevice.delete();
+            assertNull(infrastructureApi.getStorageDevice(datacenter.unwrap(), idStorageDevice));
+        }
+    }
+
+    protected void deleteMachine()
+    {
+        if (machine != null && rack != null)
+        {
+            Integer idMachine = machine.getId();
+            machine.delete();
+            assertNull(infrastructureApi.getMachine(rack.unwrap(), idMachine));
+        }
+    }
+
+    protected void deleteRack()
+    {
+        if (rack != null && datacenter != null)
+        {
+            Integer idRack = rack.getId();
+            rack.delete();
+            assertNull(infrastructureApi.getRack(datacenter.unwrap(), idRack));
+        }
+    }
+
+    protected void deleteUcsRack()
+    {
+        if (ucsRack != null && datacenter != null)
+        {
+            Integer idRack = ucsRack.getId();
+            ucsRack.delete();
+            assertNull(infrastructureApi.getManagedRack(datacenter.unwrap(), idRack));
+        }
+    }
+
+    protected void deleteDatacenter()
+    {
+        if (datacenter != null)
+        {
+            // Remove limits first
+            enterprise.prohibitDatacenter(datacenter);
+
+            Integer idDatacenter = datacenter.getId();
+            datacenter.delete(); // Abiquo API will delete remote services too
+            assertNull(infrastructureApi.getDatacenter(idDatacenter));
+        }
+    }
+
+    protected void deleteEnterprise()
+    {
+        if (enterprise != null)
+        {
+            Integer idEnterprise = enterprise.getId();
+            enterprise.delete();
+            assertNull(enterpriseApi.getEnterprise(idEnterprise));
+        }
+    }
+
+    protected void deleteLicense()
+    {
+        license.remove();
+    }
+
+    protected static String randomName()
+    {
+        return PREFIX + UUID.randomUUID().toString().substring(0, 12);
+    }
+
+    // Utility methods
+
+    public static String readLicense() throws IOException
+    {
+        URL url = CloudTestEnvironment.class.getResource("/license/expired");
+
+        return Resources.toString(url, Charset.defaultCharset());
+    }
+
+    public RemoteService findRemoteService(final RemoteServiceType type)
+    {
+        return find(remoteServices, RemoteServicePredicates.type(type));
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/TestEnvironment.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/TestEnvironment.java
new file mode 100644
index 0000000..5f74ddb
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/environment/TestEnvironment.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.environment;
+
+/**
+ * Base class fot test environment populators.
+ * <p>
+ * This class should be used to populate and clean the test environment used in live tests.
+ * 
+ * @author Ignasi Barrera
+ */
+public interface TestEnvironment
+{
+    /**
+     * Builds the test environment.
+     */
+    public void setup() throws Exception;
+
+    /**
+     * Cleans the test environment.
+     */
+    public void tearDown() throws Exception;
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/events/handlers/BlockingEventHandlerTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/events/handlers/BlockingEventHandlerTest.java
new file mode 100644
index 0000000..181157f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/events/handlers/BlockingEventHandlerTest.java
@@ -0,0 +1,125 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.events.handlers;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.events.monitor.MonitorEvent;
+import org.jclouds.abiquo.events.monitor.MonitorEvent.Type;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BlockingEventHandler} handler.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BlockingEventHandlerTest")
+public class BlockingEventHandlerTest
+{
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testConstructorWithoutObjects()
+    {
+        new BlockingEventHandler<Object>();
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testConstructorWithNullObjects()
+    {
+        new BlockingEventHandler<Object>((Object[]) null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testConstructorWithtEmptyObjects()
+    {
+        new BlockingEventHandler<Object>(new Object[] {});
+    }
+
+    public void testHandles()
+    {
+        Object object = new Object();
+        BlockingEventHandler<Object> handler = new BlockingEventHandler<Object>(object);
+
+        assertTrue(handler.handles(new MonitorEvent<Object>(Type.COMPLETED, object)));
+        assertFalse(handler.handles(new MonitorEvent<Object>(Type.COMPLETED, new Object())));
+    }
+
+    public void testReleaseDoesNothingIfNotLocked()
+    {
+        Object object = new Object();
+        BlockingEventHandler<Object> handler = new BlockingEventHandler<Object>(object);
+        handler.release(object);
+    }
+
+    public void testRelease()
+    {
+        final Object object = new Object();
+        final BlockingEventHandler<Object> handler = new BlockingEventHandler<Object>(object);
+
+        // Unlock the handler (in a separate thread) after a certain delay
+        Executors.newSingleThreadScheduledExecutor().schedule(new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                handler.release(object);
+                assertTrue(handler.lockedObjects.isEmpty());
+            }
+
+        }, 500L, TimeUnit.MILLISECONDS);
+
+        handler.lock();
+    }
+
+    public void testHandle()
+    {
+        final Object object = new Object();
+        final BlockingEventHandler<Object> handler = new BlockingEventHandler<Object>(object);
+
+        // Unlock the handler (in a separate thread) after a certain delay
+        Executors.newSingleThreadScheduledExecutor().schedule(new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                handler.handle(new MonitorEvent<Object>(Type.COMPLETED, object));
+                assertTrue(handler.lockedObjects.isEmpty());
+            }
+
+        }, 500L, TimeUnit.MILLISECONDS);
+
+        handler.lock();
+    }
+
+    public void testLockDoesNothingIfNoObjects()
+    {
+        Object object = new Object();
+        BlockingEventHandler<Object> handler = new BlockingEventHandler<Object>(object);
+        handler.lockedObjects.clear();
+
+        handler.lock(); // Lock should do nothing
+
+        assertNull(handler.completeSignal);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/AdminAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/AdminAsyncApiTest.java
new file mode 100644
index 0000000..03021b6
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/AdminAsyncApiTest.java
@@ -0,0 +1,196 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.abiquo.domain.AdminResources;
+import org.jclouds.abiquo.domain.EnterpriseResources;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.http.functions.ReleasePayloadAndReturn;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.enterprise.PrivilegesDto;
+import com.abiquo.server.core.enterprise.RoleDto;
+import com.abiquo.server.core.enterprise.RolesDto;
+import com.abiquo.server.core.enterprise.UserDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code AdminAsyncApi}
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "AdminAsyncApiTest")
+public class AdminAsyncApiTest extends BaseAbiquoAsyncApiTest<AdminAsyncApi>
+{
+    /*********************** Role ***********************/
+
+    public void testListRoles() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = AdminAsyncApi.class.getMethod("listRoles");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/admin/roles HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RolesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetRoleFromUser() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = AdminAsyncApi.class.getMethod("getRole", UserDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.userPut());
+
+        assertRequestLineEquals(request, "GET http://localhost/api/admin/roles/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RoleDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testCreateRole() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = AdminAsyncApi.class.getMethod("createRole", RoleDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, AdminResources.rolePost());
+
+        assertRequestLineEquals(request, "POST http://localhost/api/admin/roles HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RoleDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(AdminResources.rolePostPayload()), RoleDto.class,
+            RoleDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteRole() throws SecurityException, NoSuchMethodException
+    {
+        Method method = AdminAsyncApi.class.getMethod("deleteRole", RoleDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, AdminResources.rolePut());
+
+        assertRequestLineEquals(request, "DELETE http://localhost/api/admin/roles/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateRole() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = AdminAsyncApi.class.getMethod("updateRole", RoleDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, AdminResources.rolePut());
+
+        assertRequestLineEquals(request, "PUT http://localhost/api/admin/roles/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RoleDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(AdminResources.rolePutPayload()), RoleDto.class,
+            RoleDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetRoleById() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = AdminAsyncApi.class.getMethod("getRole", Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/admin/roles/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RoleDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testListPrivilegesByRoles() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = AdminAsyncApi.class.getMethod("listPrivileges", RoleDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, AdminResources.rolePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/roles/1/action/privileges HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PrivilegesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Current User **********************/
+
+    public void testGetCurrentUser() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = AdminAsyncApi.class.getMethod("getCurrentUser");
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/login HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UserDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<AdminAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<AdminAsyncApi>>()
+        {
+        };
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/BaseAbiquoAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/BaseAbiquoAsyncApiTest.java
new file mode 100644
index 0000000..9308fbb
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/BaseAbiquoAsyncApiTest.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.jclouds.Constants.PROPERTY_PRETTY_PRINT_PAYLOADS;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import org.jclouds.abiquo.AbiquoApiMetadata;
+import org.jclouds.abiquo.config.AbiquoRestClientModule;
+import org.jclouds.abiquo.http.filters.AbiquoAuthentication;
+import org.jclouds.abiquo.http.filters.AppendApiVersionToMediaType;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.providers.AnonymousProviderMetadata;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.rest.internal.BaseAsyncClientTest;
+import org.jclouds.xml.XMLParser;
+import org.testng.annotations.BeforeClass;
+
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.google.inject.Module;
+
+/**
+ * Tests annotation parsing of {@code AbiquoAsyncApi}.
+ * 
+ * @author Ignasi Barrera
+ */
+public abstract class BaseAbiquoAsyncApiTest<T> extends BaseAsyncClientTest<T>
+{
+    private XMLParser xml;
+
+    @BeforeClass
+    @Override
+    protected void setupFactory() throws IOException
+    {
+        super.setupFactory();
+        xml = injector.getInstance(XMLParser.class);
+    }
+
+    @Override
+    protected void checkFilters(final HttpRequest request)
+    {
+        assertEquals(request.getFilters().size(), 2);
+        assertEquals(request.getFilters().get(0).getClass(), AbiquoAuthentication.class);
+        assertEquals(request.getFilters().get(1).getClass(), AppendApiVersionToMediaType.class);
+    }
+
+    @Override
+    protected Module createModule()
+    {
+        return new AbiquoRestClientModule();
+    }
+
+    @Override
+    protected ProviderMetadata createProviderMetadata()
+    {
+        return AnonymousProviderMetadata.forApiWithEndpoint(new AbiquoApiMetadata(),
+            "http://localhost/api");
+    }
+
+    @Override
+    protected Properties setupProperties()
+    {
+        Properties props = super.setupProperties();
+        // Do not pretty print payloads in tests
+        props.setProperty(PROPERTY_PRETTY_PRINT_PAYLOADS, "false");
+        return props;
+    }
+
+    protected void assertPayloadEquals(final HttpRequest request, final String toMatch,
+        final Class< ? extends SingleResourceTransportDto> entityClass, final String contentType,
+        final boolean contentMD5) throws IOException
+    {
+        // Make sure we don't have formatting issues
+        SingleResourceTransportDto entity = xml.fromXML(toMatch, entityClass);
+        String stringToMatch = xml.toXML(entity, entityClass);
+
+        super.assertPayloadEquals(request, stringToMatch, contentType, contentMD5);
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/CloudAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/CloudAsyncApiTest.java
new file mode 100644
index 0000000..873be24
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/CloudAsyncApiTest.java
@@ -0,0 +1,1572 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.abiquo.domain.CloudResources;
+import org.jclouds.abiquo.domain.EnterpriseResources;
+import org.jclouds.abiquo.domain.InfrastructureResources;
+import org.jclouds.abiquo.domain.NetworkResources;
+import org.jclouds.abiquo.domain.cloud.options.VirtualDatacenterOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineTemplateOptions;
+import org.jclouds.abiquo.domain.cloud.options.VolumeOptions;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.domain.options.search.reference.OrderBy;
+import org.jclouds.abiquo.functions.ReturnTaskReferenceOrNull;
+import org.jclouds.abiquo.functions.cloud.ReturnMovedVolume;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.http.functions.ReleasePayloadAndReturn;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.model.transport.LinksDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualApplianceStateDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.abiquo.server.core.cloud.VirtualDatacenterDto;
+import com.abiquo.server.core.cloud.VirtualDatacentersDto;
+import com.abiquo.server.core.cloud.VirtualMachineDto;
+import com.abiquo.server.core.cloud.VirtualMachineStateDto;
+import com.abiquo.server.core.cloud.VirtualMachineTaskDto;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpDto;
+import com.abiquo.server.core.infrastructure.network.PrivateIpsDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.abiquo.server.core.infrastructure.network.VMNetworkConfigurationsDto;
+import com.abiquo.server.core.infrastructure.storage.DiskManagementDto;
+import com.abiquo.server.core.infrastructure.storage.DisksManagementDto;
+import com.abiquo.server.core.infrastructure.storage.MovedVolumeDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.abiquo.server.core.infrastructure.storage.VolumesManagementDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code CloudAsyncApi}
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "CloudAsyncApiTest")
+public class CloudAsyncApiTest extends BaseAbiquoAsyncApiTest<CloudAsyncApi>
+{
+    /*********************** Virtual Datacenter ***********************/
+
+    public void testListVirtualDatacentersParams() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listVirtualDatacenters", VirtualDatacenterOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, VirtualDatacenterOptions.builder().datacenterId(1)
+                .enterpriseId(1).build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters?datacenter=1&enterprise=1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualDatacentersDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVirtualDatacentersNoParams() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listVirtualDatacenters", VirtualDatacenterOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, VirtualDatacenterOptions.builder().build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualDatacentersDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateVirtualDatacenter() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("createVirtualDatacenter", VirtualDatacenterDto.class,
+                DatacenterDto.class, EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPost(),
+                InfrastructureResources.datacenterPut(), EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters?enterprise=1&datacenter=1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualDatacenterDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualDatacenterPostPayload()),
+            VirtualDatacenterDto.class, VirtualDatacenterDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetVirtualDatacenter() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("getVirtualDatacenter", Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualDatacenterDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateVirtualDatacenter() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("updateVirtualDatacenter", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualDatacenterDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualDatacenterPutPayload()),
+            VirtualDatacenterDto.class, VirtualDatacenterDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteVirtualDatacenter() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("deleteVirtualDatacenter", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/cloud/virtualdatacenters/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Ips ***********************/
+
+    public void testListAvailablePublicIpsWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        IpOptions options = IpOptions.builder().limit(5).build();
+        Method method =
+            CloudAsyncApi.class.getMethod("listAvailablePublicIps", VirtualDatacenterDto.class,
+                IpOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/publicips/topurchase?limit=5 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PublicIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListPurchasedPublicIpsWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        IpOptions options = IpOptions.builder().limit(5).build();
+        Method method =
+            CloudAsyncApi.class.getMethod("listPurchasedPublicIps", VirtualDatacenterDto.class,
+                IpOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/publicips/purchased?limit=5 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PublicIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testPurchasePublicIp() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("purchasePublicIp", PublicIpDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.publicIpToPurchase());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/5/publicips/purchased/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PublicIpDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testReleasePublicIp() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("releasePublicIp", PublicIpDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.publicIpToRelease());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/5/publicips/topurchase/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PublicIpDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Available templates ***********************/
+
+    public void testListAvailableTemplates() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listAvailableTemplates", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/action/templates HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineTemplatesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListAvailableTemplatesWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listAvailableTemplates", VirtualDatacenterDto.class,
+                VirtualMachineTemplateOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(),
+                VirtualMachineTemplateOptions.builder().hypervisorType(HypervisorType.XENSERVER)
+                    .categoryName("Firewalls").idTemplate(1).build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/action/templates"
+                + "?hypervisorTypeName=XENSERVER&categoryName=Firewalls&idTemplate=1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineTemplatesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Storage Tiers ***********************/
+
+    public void testListStorageTiers() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listStorageTiers", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/tiers HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TiersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetStorageTier() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getStorageTier", VirtualDatacenterDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/tiers/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TierDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testGetDefaultNetwork() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getDefaultNetwork", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworkDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testSetDefaultNetworkInternal() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("setDefaultNetwork", VirtualDatacenterDto.class,
+                VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(),
+                NetworkResources.privateNetworkPut());
+
+        RESTLink netLink = NetworkResources.privateNetworkPut().getEditLink();
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/action/defaultvlan HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, withHeader("<links><link href=\"" + netLink.getHref()
+            + "\" rel=\"internalnetwork\"/></links>"), LinksDto.class, LinksDto.BASE_MEDIA_TYPE,
+            false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testSetDefaultNetworkExternal() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("setDefaultNetwork", VirtualDatacenterDto.class,
+                VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(),
+                NetworkResources.externalNetworkPut());
+
+        RESTLink netLink = NetworkResources.externalNetworkPut().getEditLink();
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/action/defaultvlan HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, withHeader("<links><link href=\"" + netLink.getHref()
+            + "\" rel=\"externalnetwork\"/></links>"), LinksDto.class, LinksDto.BASE_MEDIA_TYPE,
+            false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Private Network ***********************/
+
+    public void testListPrivateNetworks() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listPrivateNetworks", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/privatenetworks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworksDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetPrivateNetwork() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getPrivateNetwork", VirtualDatacenterDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworkDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testCreatePrivateNetwork() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("createPrivateNetwork", VirtualDatacenterDto.class,
+                VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(),
+                NetworkResources.vlanPost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/privatenetworks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworkDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(NetworkResources.vlanNetworkPostPayload()),
+            VLANNetworkDto.class, VLANNetworkDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdatePrivateNetwork() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("updatePrivateNetwork", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.privateNetworkPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworkDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(NetworkResources.privateNetworkPutPayload()),
+            VLANNetworkDto.class, VLANNetworkDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeletePrivateNetwork() throws SecurityException, NoSuchMethodException
+    {
+        Method method = CloudAsyncApi.class.getMethod("deletePrivateNetwork", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.privateNetworkPut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Private Network IPs ***********************/
+
+    public void testListPrivateNetworkIps() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listPrivateNetworkIps", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.privateNetworkPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1/ips HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PrivateIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListPrivateNetworkIpsWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        IpOptions options = IpOptions.builder().startWith(10).build();
+        Method method =
+            CloudAsyncApi.class.getMethod("listPrivateNetworkIps", VLANNetworkDto.class,
+                IpOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.privateNetworkPut(), options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1/ips?startwith=10 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PrivateIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetPrivateNetworkIp() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getPrivateNetworkIp", VLANNetworkDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.privateNetworkPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/privatenetworks/1/ips/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PrivateIpDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Virtual Appliance ***********************/
+
+    public void testListVirtualAppliances() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listVirtualAppliances", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualAppliancesDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetVirtualAppliance() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getVirtualAppliance", VirtualDatacenterDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualApplianceDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testGetVirtualApplianceState() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getVirtualApplianceState", VirtualApplianceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/state HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualApplianceStateDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateVirtualAppliance() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("createVirtualAppliance", VirtualDatacenterDto.class,
+                VirtualApplianceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(),
+                CloudResources.virtualAppliancePost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/virtualappliances HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualApplianceDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualAppliancePostPayload()),
+            VirtualApplianceDto.class, VirtualApplianceDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateVirtualAppliance() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("updateVirtualAppliance", VirtualApplianceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualApplianceDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualAppliancePutPayload()),
+            VirtualApplianceDto.class, VirtualApplianceDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteVirtualAppliance() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("deleteVirtualAppliance", VirtualApplianceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeployVirtualAppliance() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("deployVirtualAppliance", VirtualApplianceDto.class,
+                VirtualMachineTaskDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut(),
+                CloudResources.deployOptions());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/action/deploy HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.deployPayload()),
+            VirtualMachineTaskDto.class, VirtualMachineTaskDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUndeployVirtualAppliance() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("undeployVirtualAppliance", VirtualApplianceDto.class,
+                VirtualMachineTaskDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut(),
+                CloudResources.undeployOptions());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/action/undeploy HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.undeployPayload()),
+            VirtualMachineTaskDto.class, VirtualMachineTaskDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Virtual Machine ***********************/
+
+    public void testListVirtualMachines() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listVirtualMachines", VirtualApplianceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVirtualMachinesWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listVirtualMachines", VirtualApplianceDto.class,
+                VirtualMachineOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut(),
+                VirtualMachineOptions.builder().disablePagination().build());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines?limit=0 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetVirtualMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getVirtualMachine", VirtualApplianceDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut(), 1);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testCreateVirtualMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("createVirtualMachine", VirtualApplianceDto.class,
+                VirtualMachineWithNodeExtendedDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualAppliancePut(),
+                CloudResources.virtualMachinePost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualMachinePostPayload()),
+            VirtualMachineWithNodeExtendedDto.class,
+            VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateVirtualMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("updateVirtualMachine",
+                VirtualMachineWithNodeExtendedDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualMachinePutPayload()),
+            VirtualMachineWithNodeExtendedDto.class,
+            VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTaskReferenceOrNull.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateVirtualMachineWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("updateVirtualMachine",
+                VirtualMachineWithNodeExtendedDto.class, VirtualMachineOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut(),
+                VirtualMachineOptions.builder().force(true).build());
+
+        assertRequestLineEquals(
+            request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1?force=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualMachinePutPayload()),
+            VirtualMachineWithNodeExtendedDto.class,
+            VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTaskReferenceOrNull.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testChangeVirtualMachineState() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("changeVirtualMachineState", VirtualMachineDto.class,
+                VirtualMachineStateDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut(),
+                CloudResources.virtualMachineState());
+
+        assertRequestLineEquals(
+            request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/state HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualMachineStatePayload()),
+            VirtualMachineStateDto.class, VirtualMachineStateDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteVirtualMachine() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("deleteVirtualMachine", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "DELETE http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetVirtualMachineState() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getVirtualMachineState", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/state HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualMachineStateDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeployVirtualMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("deployVirtualMachine", VirtualMachineDto.class,
+                VirtualMachineTaskDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut(),
+                CloudResources.deployOptions());
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/deploy HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.deployPayload()),
+            VirtualMachineTaskDto.class, VirtualMachineTaskDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUndeployVirtualMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("undeployVirtualMachine", VirtualMachineDto.class,
+                VirtualMachineTaskDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut(),
+                CloudResources.undeployOptions());
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/undeploy HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.undeployPayload()),
+            VirtualMachineTaskDto.class, VirtualMachineTaskDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testRebootVirtualMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("rebootVirtualMachine", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/reset HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListNetworkConfigurations() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listNetworkConfigurations", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/network/configurations HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VMNetworkConfigurationsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testSetGatewayNetwork() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("setGatewayNetwork", VirtualMachineDto.class,
+                VLANNetworkDto.class);
+
+        VirtualMachineDto vm = CloudResources.virtualMachinePut();
+        VLANNetworkDto network = NetworkResources.privateNetworkPut();
+
+        GeneratedHttpRequest request = processor.createRequest(method, vm, network);
+
+        String configLink = vm.searchLink("configurations").getHref() + "/" + network.getId();
+
+        assertRequestLineEquals(
+            request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/network/configurations HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, withHeader("<links><link href=\"" + configLink
+            + "\" rel=\"network_configuration\"/></links>"), LinksDto.class,
+            LinksDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Virtual Machine Template ***********************/
+
+    public void testGetVirtualMachineTemplate() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getVirtualMachineTemplate", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineTemplateDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListAttachedVolumes() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listAttachedVolumes", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/volumes HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VolumesManagementDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDetachAllVolumes() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("detachAllVolumes", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "DELETE http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/volumes HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTaskReferenceOrNull.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testReplaceVolumes() throws SecurityException, NoSuchMethodException, IOException
+    {
+        VolumeManagementDto first = CloudResources.volumePut();
+        VolumeManagementDto second = CloudResources.volumePut();
+        second.getEditLink().setHref(second.getEditLink().getHref() + "second");
+
+        Method method =
+            CloudAsyncApi.class.getMethod("replaceVolumes", VirtualMachineDto.class,
+                VirtualMachineOptions.class, VolumeManagementDto[].class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut(),
+                VirtualMachineOptions.builder().force(true).build(), new VolumeManagementDto[] {
+                first, second});
+
+        String editLink = CloudResources.volumePut().getEditLink().getHref();
+        assertRequestLineEquals(
+            request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/volumes?force=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader("<links><link href=\"" + editLink
+            + "\" rel=\"volume\"/><link href=\"" + editLink + "second\" rel=\"volume\"/></links>"),
+            LinksDto.class, LinksDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTaskReferenceOrNull.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListAttachedHardDisks() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listAttachedHardDisks", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/disks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DisksManagementDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDetachAllHardDisks() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("detachAllHardDisks", VirtualMachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "DELETE http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/disks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTaskReferenceOrNull.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testReplaceHardDisks() throws SecurityException, NoSuchMethodException, IOException
+    {
+        DiskManagementDto first = CloudResources.hardDiskPut();
+        DiskManagementDto second = CloudResources.hardDiskPut();
+        second.getEditLink().setHref(second.getEditLink().getHref() + "second");
+
+        Method method =
+            CloudAsyncApi.class.getMethod("replaceHardDisks", VirtualMachineDto.class,
+                DiskManagementDto[].class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut(),
+                new DiskManagementDto[] {first, second});
+
+        String editLink = CloudResources.hardDiskPut().getEditLink().getHref();
+        assertRequestLineEquals(
+            request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/storage/disks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader("<links><link href=\"" + editLink
+            + "\" rel=\"disk\"/><link href=\"" + editLink + "second\" rel=\"disk\"/></links>"),
+            LinksDto.class, LinksDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTaskReferenceOrNull.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Hard disks ***********************/
+
+    public void testListHardDisks() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("listHardDisks", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/disks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DisksManagementDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetHardDisk() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getHardDisk", VirtualDatacenterDto.class, Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/disks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DiskManagementDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testCreateHardDisk() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("createHardDisk", VirtualDatacenterDto.class,
+                DiskManagementDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(),
+                CloudResources.hardDiskPost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/disks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DiskManagementDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.hardDiskPostPayload()),
+            DiskManagementDto.class, DiskManagementDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteHardDisk() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("deleteHardDisk", DiskManagementDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.hardDiskPut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/cloud/virtualdatacenters/1/disks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Volumes ***********************/
+
+    public void testListVolumes() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("listVolumes", VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/volumes HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VolumesManagementDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVolumesWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listVolumes", VirtualDatacenterDto.class,
+                VolumeOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), VolumeOptions
+                .builder().onlyAvailable(true).build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/volumes?available=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VolumesManagementDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVolumesWithFilterOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("listVolumes", VirtualDatacenterDto.class,
+                VolumeOptions.class);
+
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), VolumeOptions
+                .builder().has("vol").orderBy(OrderBy.NAME).ascendant(true).build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/volumes?has=vol&by=name&asc=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VolumesManagementDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetVolume() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("getVolume", VirtualDatacenterDto.class, Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/volumes/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VolumeManagementDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testCreateVolume() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("createVolume", VirtualDatacenterDto.class,
+                VolumeManagementDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualDatacenterPut(),
+                CloudResources.volumePost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/volumes HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VolumeManagementDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.volumePostPayload()),
+            VolumeManagementDto.class, VolumeManagementDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateVolume() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("updateVolume", VolumeManagementDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, CloudResources.volumePut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/cloud/virtualdatacenters/1/volumes/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.volumePutPayload()),
+            VolumeManagementDto.class, VolumeManagementDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTaskReferenceOrNull.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteVolume() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = CloudAsyncApi.class.getMethod("deleteVolume", VolumeManagementDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, CloudResources.volumePut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/cloud/virtualdatacenters/1/volumes/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testMoveVolume() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            CloudAsyncApi.class.getMethod("moveVolume", VolumeManagementDto.class,
+                VirtualDatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.volumePut(),
+                CloudResources.virtualDatacenterPut());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/cloud/virtualdatacenters/1/volumes/1/action/move HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MovedVolumeDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(CloudResources.virtualDatacenterRefPayload()),
+            LinksDto.class, LinksDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnMovedVolume.class);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<CloudAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<CloudAsyncApi>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/ConfigAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/ConfigAsyncApiTest.java
new file mode 100644
index 0000000..0352472
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/ConfigAsyncApiTest.java
@@ -0,0 +1,317 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.abiquo.domain.ConfigResources;
+import org.jclouds.abiquo.domain.config.options.LicenseOptions;
+import org.jclouds.abiquo.domain.config.options.PropertyOptions;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.http.functions.ReleasePayloadAndReturn;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.appslibrary.CategoriesDto;
+import com.abiquo.server.core.appslibrary.CategoryDto;
+import com.abiquo.server.core.config.LicenseDto;
+import com.abiquo.server.core.config.LicensesDto;
+import com.abiquo.server.core.config.SystemPropertiesDto;
+import com.abiquo.server.core.config.SystemPropertyDto;
+import com.abiquo.server.core.enterprise.PrivilegeDto;
+import com.abiquo.server.core.enterprise.PrivilegesDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code AdminAsyncApi}.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "ConfigAsyncApiTest")
+public class ConfigAsyncApiTest extends BaseAbiquoAsyncApiTest<ConfigAsyncApi>
+{
+    /*********************** License ***********************/
+
+    public void testListLicenses() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("listLicenses");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/config/licenses HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + LicensesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListLicenseWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("listLicenses", LicenseOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, LicenseOptions.builder().active(true).build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/config/licenses?active=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + LicensesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testAddLicense() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("addLicense", LicenseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, ConfigResources.licensePost());
+
+        assertRequestLineEquals(request, "POST http://localhost/api/config/licenses HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + LicenseDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(ConfigResources.licensePostPayload()),
+            LicenseDto.class, LicenseDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testRemoveLicense() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("removeLicense", LicenseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, ConfigResources.licensePut());
+
+        assertRequestLineEquals(request, "DELETE http://localhost/api/config/licenses/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Privilege ***********************/
+
+    public void testListPrivileges() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("listPrivileges");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/config/privileges HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PrivilegesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetPrivilege() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("getPrivilege", Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/config/privileges/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PrivilegeDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    /*********************** System Properties ***********************/
+
+    public void testListSystemProperties() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("listSystemProperties");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/config/properties HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + SystemPropertiesDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListSystemPropertiesWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            ConfigAsyncApi.class.getMethod("listSystemProperties", PropertyOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, PropertyOptions.builder().component("api").build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/config/properties?component=api HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + SystemPropertiesDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateSystemProperty() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            ConfigAsyncApi.class.getMethod("updateSystemProperty", SystemPropertyDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, ConfigResources.propertyPut());
+
+        assertRequestLineEquals(request, "PUT http://localhost/api/config/properties/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + SystemPropertyDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(ConfigResources.propertyPutPayload()),
+            SystemPropertyDto.class, SystemPropertyDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Category ***********************/
+
+    public void testListCategories() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("listCategories");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/config/categories HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + CategoriesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetCategory() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("getCategory", Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/config/categories/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + CategoryDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testCreateCategory() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("createCategory", CategoryDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, ConfigResources.categoryPost());
+
+        assertRequestLineEquals(request, "POST http://localhost/api/config/categories HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + CategoryDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(ConfigResources.categoryPostPayload()),
+            CategoryDto.class, CategoryDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateCategory() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("updateCategory", CategoryDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, ConfigResources.categoryPut());
+
+        assertRequestLineEquals(request, "PUT http://localhost/api/config/categories/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + CategoryDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(ConfigResources.categoryPutPayload()),
+            CategoryDto.class, CategoryDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteCategory() throws SecurityException, NoSuchMethodException
+    {
+        Method method = ConfigAsyncApi.class.getMethod("deleteCategory", CategoryDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, ConfigResources.categoryPut());
+
+        assertRequestLineEquals(request, "DELETE http://localhost/api/config/categories/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<ConfigAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<ConfigAsyncApi>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/EnterpriseAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/EnterpriseAsyncApiTest.java
new file mode 100644
index 0000000..2a6a79c
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/EnterpriseAsyncApiTest.java
@@ -0,0 +1,807 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.abiquo.domain.EnterpriseResources;
+import org.jclouds.abiquo.domain.InfrastructureResources;
+import org.jclouds.abiquo.domain.enterprise.options.EnterpriseOptions;
+import org.jclouds.abiquo.domain.options.search.reference.OrderBy;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.http.functions.ReleasePayloadAndReturn;
+import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.am.model.TemplatesStateDto;
+import com.abiquo.server.core.appslibrary.DatacenterRepositoryDto;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListDto;
+import com.abiquo.server.core.appslibrary.TemplateDefinitionListsDto;
+import com.abiquo.server.core.cloud.VirtualAppliancesDto;
+import com.abiquo.server.core.cloud.VirtualDatacentersDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.DatacenterLimitsDto;
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.enterprise.EnterprisePropertiesDto;
+import com.abiquo.server.core.enterprise.EnterprisesDto;
+import com.abiquo.server.core.enterprise.UserDto;
+import com.abiquo.server.core.enterprise.UsersDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code EnterpriseAsyncApi}
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "EnterpriseAsyncApiTest")
+public class EnterpriseAsyncApiTest extends BaseAbiquoAsyncApiTest<EnterpriseAsyncApi>
+{
+    /*********************** Enterprise ********************** */
+
+    public void testListEnterprises() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("listEnterprises");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/admin/enterprises HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EnterprisesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListEnterprisesWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        EnterpriseOptions options =
+            EnterpriseOptions.builder().has("abi").orderBy(OrderBy.NAME).ascendant(true).build();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listEnterprises", EnterpriseOptions.class);
+        GeneratedHttpRequest request = processor.createRequest(method, options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises?has=abi&by=name&asc=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EnterprisesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListEnterprisesByDatacenter() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        EnterpriseOptions options =
+            EnterpriseOptions.builder().startWith(0).limit(25).network(true).build();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listEnterprises", DatacenterDto.class,
+                EnterpriseOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), options);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/datacenters/1/action/enterprises?network=true&startwith=0&limit=25 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EnterprisesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateEnterprise() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("createEnterprise", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePost());
+
+        assertRequestLineEquals(request, "POST http://localhost/api/admin/enterprises HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EnterpriseDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(EnterpriseResources.enterprisePostPayload()),
+            EnterpriseDto.class, EnterpriseDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetEnterprise() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("getEnterprise", Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/admin/enterprises/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EnterpriseDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateEnterprise() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("updateEnterprise", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request, "PUT http://localhost/api/admin/enterprises/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EnterpriseDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(EnterpriseResources.enterprisePutPayload()),
+            EnterpriseDto.class, EnterpriseDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteEnterprise() throws SecurityException, NoSuchMethodException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("deleteEnterprise", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request, "DELETE http://localhost/api/admin/enterprises/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListAllowedDatacenters() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("listAllowedDatacenters", Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters?idEnterprise=1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacentersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVirtualDatacentersFromEnterprise() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listVirtualDatacenters", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/action/virtualdatacenters HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualDatacentersDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Enterprise Properties ********************** */
+
+    public void testGetEnterpriseProperties() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("getEnterpriseProperties", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/properties HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EnterprisePropertiesDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateEnterpriseProperties() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("updateEnterpriseProperties",
+                EnterprisePropertiesDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePropertiesPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/enterprises/1/properties HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EnterprisePropertiesDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request,
+            withHeader(EnterpriseResources.enterprisePropertiesPutPayload()),
+            EnterprisePropertiesDto.class, EnterprisePropertiesDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Enterprise Limits ********************** */
+
+    public void testCreateLimits() throws SecurityException, NoSuchMethodException, IOException
+    {
+        EnterpriseDto enterprise = EnterpriseResources.enterprisePut();
+        DatacenterDto datacenter = InfrastructureResources.datacenterPut();
+        DatacenterLimitsDto limits = EnterpriseResources.datacenterLimitsPost();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("createLimits", EnterpriseDto.class,
+                DatacenterDto.class, DatacenterLimitsDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, enterprise, datacenter, limits);
+
+        String limitsUri = enterprise.searchLink("limits").getHref();
+        String requestURI =
+            String.format("POST %s?datacenter=%d HTTP/1.1", limitsUri, datacenter.getId());
+
+        assertRequestLineEquals(request, requestURI);
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacenterLimitsDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(EnterpriseResources.datacenterLimitsPostPayload()),
+            DatacenterLimitsDto.class, DatacenterLimitsDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetLimits() throws SecurityException, NoSuchMethodException, IOException
+    {
+        EnterpriseDto enterprise = EnterpriseResources.enterprisePut();
+        DatacenterDto datacenter = InfrastructureResources.datacenterPut();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("getLimits", EnterpriseDto.class,
+                DatacenterDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, enterprise, datacenter);
+
+        String limitsUri = enterprise.searchLink("limits").getHref();
+        String requestURI =
+            String.format("GET %s?datacenter=%d HTTP/1.1", limitsUri, datacenter.getId());
+
+        assertRequestLineEquals(request, requestURI);
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacentersLimitsDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateLimits() throws SecurityException, NoSuchMethodException, IOException
+    {
+        EnterpriseDto enterprise = EnterpriseResources.enterprisePut();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("updateLimits", DatacenterLimitsDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.datacenterLimitsPut(enterprise));
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/enterprises/1/limits/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacenterLimitsDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request,
+            withHeader(EnterpriseResources.datacenterLimitsPutPayload(enterprise)),
+            DatacenterLimitsDto.class, DatacenterLimitsDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteLimits() throws SecurityException, NoSuchMethodException
+    {
+        EnterpriseDto enterprise = EnterpriseResources.enterprisePut();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("deleteLimits", DatacenterLimitsDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.datacenterLimitsPut(enterprise));
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/enterprises/1/limits/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListLimitsEnterprise() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("listLimits", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/limits HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacentersLimitsDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** User ***********************/
+
+    public void testGetUser() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("getUser", EnterpriseDto.class, Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/users/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UserDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testListUsers() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("listUsers", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/users HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UsersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateUser() throws SecurityException, NoSuchMethodException, IOException
+    {
+        EnterpriseDto enterprise = EnterpriseResources.enterprisePut();
+        UserDto user = EnterpriseResources.userPost();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("createUser", EnterpriseDto.class, UserDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, enterprise, user);
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/enterprises/1/users HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UserDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(EnterpriseResources.userPostPayload()),
+            UserDto.class, UserDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateUser() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("updateUser", UserDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.userPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/enterprises/1/users/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UserDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(EnterpriseResources.userPutPayload()),
+            UserDto.class, UserDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteUser() throws SecurityException, NoSuchMethodException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("deleteUser", UserDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.userPut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/enterprises/1/users/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVirtualMachinesByUser() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = EnterpriseAsyncApi.class.getMethod("listVirtualMachines", UserDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.userPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/users/1/action/virtualmachines HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Datacenter Repository ********************** */
+
+    public void testGetDatacenterRepository() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("getDatacenterRepository", EnterpriseDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut(),
+                InfrastructureResources.datacenterPut().getId());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacenterRepositoryDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testRefreshTemplateRepository() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("refreshTemplateRepository", Integer.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut().getId(),
+                InfrastructureResources.datacenterPut().getId());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/enterprises/1/datacenterrepositories/1/actions/refresh HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** External Network ********************** */
+
+    public void testListExternalNetworks() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listExternalNetworks", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/action/externalnetworks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworksDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Cloud ********************** */
+
+    public void testListVirtualMachines() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listVirtualMachines", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/action/virtualmachines HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVirtualAppliances() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listVirtualAppliances", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/action/virtualappliances HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VirtualAppliancesDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Machine ********************** */
+
+    public void testListReservedMachines() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listReservedMachines", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/reservedmachines HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachinesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Template definition list ***********************/
+
+    public void testListTemplateDefinitionLists() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listTemplateDefinitionLists", EnterpriseDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + TemplateDefinitionListsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateTemplateDefinitionList() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        EnterpriseDto enterprise = EnterpriseResources.enterprisePut();
+        TemplateDefinitionListDto template = EnterpriseResources.templateListPost();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("createTemplateDefinitionList", EnterpriseDto.class,
+                TemplateDefinitionListDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, enterprise, template);
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + TemplateDefinitionListDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(EnterpriseResources.templateListPostPayload()),
+            TemplateDefinitionListDto.class, TemplateDefinitionListDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateTemplateDefinitionList() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        TemplateDefinitionListDto template = EnterpriseResources.templateListPut();
+
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("updateTemplateDefinitionList",
+                TemplateDefinitionListDto.class);
+        GeneratedHttpRequest request = processor.createRequest(method, template);
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + TemplateDefinitionListDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(EnterpriseResources.templateListPutPayload()),
+            TemplateDefinitionListDto.class, TemplateDefinitionListDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteTemplateDefinitionList() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("deleteTemplateDefinitionList",
+                TemplateDefinitionListDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.templateListPut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetTemplateDefinitionList() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("getTemplateDefinitionList", EnterpriseDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + TemplateDefinitionListDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testListTemplateListStatus() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            EnterpriseAsyncApi.class.getMethod("listTemplateListStatus",
+                TemplateDefinitionListDto.class, DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.templateListPut(),
+                InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/appslib/templateDefinitionLists/1/actions/repositoryStatus?datacenterId=1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TemplatesStateDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<EnterpriseAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<EnterpriseAsyncApi>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/EventAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/EventAsyncApiTest.java
new file mode 100644
index 0000000..bd837ff
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/EventAsyncApiTest.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.event.EventsDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code EventAsyncApi}
+ * 
+ * @author Ignasi Barrera
+ * @author Vivien Mahé
+ */
+@Test(groups = "unit", testName = "EventAsyncApiTest")
+public class EventAsyncApiTest extends BaseAbiquoAsyncApiTest<EventAsyncApi>
+{
+    public void testListEvents() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = EventAsyncApi.class.getMethod("listEvents");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/events HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + EventsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<EventAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<EventAsyncApi>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/FeatureCoverageTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/FeatureCoverageTest.java
new file mode 100644
index 0000000..5215f0f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/FeatureCoverageTest.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.jclouds.abiquo.config.AbiquoRestClientModule;
+import org.jclouds.abiquo.rest.internal.AbiquoHttpAsyncClient;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+
+/**
+ * Tests that all features have a unit test.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "FeatureCoverageTest")
+public class FeatureCoverageTest
+{
+    /** A collection with all async api classes. */
+    private Collection<Class< ? >> featureClasses;
+
+    @BeforeMethod
+    public void setup()
+    {
+        featureClasses = new ArrayList<Class< ? >>();
+        featureClasses.addAll(AbiquoRestClientModule.DELEGATE_MAP.values());
+        featureClasses.add(AbiquoHttpAsyncClient.class);
+    }
+
+    public void testAllFeaturesHaveTest() throws ClassNotFoundException
+    {
+        List<String> missingTests = new ArrayList<String>();
+
+        for (Class< ? > featureClass : featureClasses)
+        {
+            try
+            {
+                Class< ? > testClass = loadTestClass(featureClass);
+                Iterable<String> testMethodNames = methodNames(testClass);
+
+                for (Method method : featureClass.getMethods())
+                {
+                    if (!hasTest(testMethodNames, method))
+                    {
+                        missingTests.add(method.getDeclaringClass().getSimpleName() + "."
+                            + method.getName());
+                    }
+                }
+            }
+            catch (ClassNotFoundException ex)
+            {
+                fail("Missing tests for class: " + featureClass.getName());
+            }
+        }
+
+        assertTrue(missingTests.isEmpty(), "Missing tests: " + Joiner.on(", ").join(missingTests));
+    }
+
+    private Class< ? > loadTestClass(final Class< ? > featureClass) throws ClassNotFoundException
+    {
+        String testClassName = featureClass.getName() + "Test";
+        return Thread.currentThread().getContextClassLoader().loadClass(testClassName);
+    }
+
+    private static Iterable<String> methodNames(final Class< ? > clazz)
+    {
+        return Iterables.transform(Arrays.asList(clazz.getMethods()),
+            new Function<Method, String>()
+            {
+                @Override
+                public String apply(final Method input)
+                {
+                    return input.getName();
+                }
+            });
+    }
+
+    private static boolean hasTest(final Iterable<String> testMethodNames, final Method method)
+    {
+        String testMethod = Iterables.find(testMethodNames, new Predicate<String>()
+        {
+            @Override
+            public boolean apply(final String input)
+            {
+                return input.toLowerCase().contains(method.getName().toLowerCase());
+            }
+        }, null);
+
+        return testMethod != null;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/InfrastructureAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/InfrastructureAsyncApiTest.java
new file mode 100644
index 0000000..ab5b294
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/InfrastructureAsyncApiTest.java
@@ -0,0 +1,2137 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.abiquo.domain.EnterpriseResources;
+import org.jclouds.abiquo.domain.InfrastructureResources;
+import org.jclouds.abiquo.domain.NetworkResources;
+import org.jclouds.abiquo.domain.infrastructure.options.DatacenterOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.IpmiOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.MachineOptions;
+import org.jclouds.abiquo.domain.infrastructure.options.StoragePoolOptions;
+import org.jclouds.abiquo.domain.network.options.IpOptions;
+import org.jclouds.abiquo.domain.network.options.NetworkOptions;
+import org.jclouds.abiquo.domain.options.search.FilterOptions;
+import org.jclouds.abiquo.functions.ReturnAbiquoExceptionOnNotFoundOr4xx;
+import org.jclouds.abiquo.functions.ReturnFalseIfNotAvailable;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.http.functions.ReleasePayloadAndReturn;
+import org.jclouds.http.functions.ReturnStringIf2xx;
+import org.jclouds.http.functions.ReturnTrueIf2xx;
+import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.enumerator.NetworkType;
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.abiquo.server.core.cloud.HypervisorTypesDto;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.cloud.VirtualMachinesWithNodeExtendedDto;
+import com.abiquo.server.core.enterprise.DatacentersLimitsDto;
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.abiquo.server.core.infrastructure.BladeLocatorLedDto;
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.abiquo.server.core.infrastructure.FsmsDto;
+import com.abiquo.server.core.infrastructure.LogicServerDto;
+import com.abiquo.server.core.infrastructure.LogicServersDto;
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.abiquo.server.core.infrastructure.MachineIpmiStateDto;
+import com.abiquo.server.core.infrastructure.MachineStateDto;
+import com.abiquo.server.core.infrastructure.MachinesDto;
+import com.abiquo.server.core.infrastructure.OrganizationDto;
+import com.abiquo.server.core.infrastructure.OrganizationsDto;
+import com.abiquo.server.core.infrastructure.RackDto;
+import com.abiquo.server.core.infrastructure.RacksDto;
+import com.abiquo.server.core.infrastructure.RemoteServiceDto;
+import com.abiquo.server.core.infrastructure.RemoteServicesDto;
+import com.abiquo.server.core.infrastructure.UcsRackDto;
+import com.abiquo.server.core.infrastructure.UcsRacksDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpDto;
+import com.abiquo.server.core.infrastructure.network.ExternalIpsDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpDto;
+import com.abiquo.server.core.infrastructure.network.PublicIpsDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpDto;
+import com.abiquo.server.core.infrastructure.network.UnmanagedIpsDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworkDto;
+import com.abiquo.server.core.infrastructure.network.VLANNetworksDto;
+import com.abiquo.server.core.infrastructure.network.VlanTagAvailabilityDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDeviceDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDevicesDto;
+import com.abiquo.server.core.infrastructure.storage.StorageDevicesMetadataDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolDto;
+import com.abiquo.server.core.infrastructure.storage.StoragePoolsDto;
+import com.abiquo.server.core.infrastructure.storage.TierDto;
+import com.abiquo.server.core.infrastructure.storage.TiersDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code InfrastructureAsyncApi}
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "InfrastructureAsyncApiTest")
+public class InfrastructureAsyncApiTest extends BaseAbiquoAsyncApiTest<InfrastructureAsyncApi>
+{
+    /*********************** Datacenter ***********************/
+
+    public void testListDatacenters() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("listDatacenters");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/admin/datacenters HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacentersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateDatacenter() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("createDatacenter", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPost());
+
+        assertRequestLineEquals(request, "POST http://localhost/api/admin/datacenters HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacenterDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.datacenterPostPayload()),
+            DatacenterDto.class, DatacenterDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetDatacenter() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("getDatacenter", Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/admin/datacenters/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacenterDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateDatacenter() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("updateDatacenter", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request, "PUT http://localhost/api/admin/datacenters/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacenterDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.datacenterPutPayload()),
+            DatacenterDto.class, DatacenterDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteDatacenter() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("deleteDatacenter", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request, "DELETE http://localhost/api/admin/datacenters/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListLimitsDatacenter() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("listLimits", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/action/getLimits HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacentersLimitsDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Hypervisor ***********************/
+
+    public void testGetHypervisorTypeFromMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getHypervisorTypeFromMachine",
+                DatacenterDto.class, DatacenterOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(),
+                DatacenterOptions.builder().ip("10.60.1.120").build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/action/hypervisor?ip=10.60.1.120 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MediaType.TEXT_PLAIN + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReturnStringIf2xx.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetHypervisorTypesFromDatacenter() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getHypervisorTypes", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/hypervisors HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + HypervisorTypesDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Managed Rack ***********************/
+
+    public void testListRacks() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("listRacks", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RacksDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateRack() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class
+                .getMethod("createRack", DatacenterDto.class, RackDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(),
+                InfrastructureResources.rackPost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/racks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RackDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.rackPostPayload()),
+            RackDto.class, RackDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetRack() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getRack", DatacenterDto.class, Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RackDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateRack() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("updateRack", RackDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.rackPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/racks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RackDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.rackPutPayload()),
+            RackDto.class, RackDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteRack() throws SecurityException, NoSuchMethodException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("deleteRack", RackDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.rackPut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/datacenters/1/racks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Managed Rack ***********************/
+
+    public void testListManagedRacks() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listManagedRacks", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UcsRacksDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateManagedRack() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("createManagedRack", DatacenterDto.class,
+                UcsRackDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(),
+                InfrastructureResources.managedRackPost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/racks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UcsRackDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.managedRackPostPayload()),
+            UcsRackDto.class, UcsRackDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetManagedRack() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getManagedRack", DatacenterDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UcsRackDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateManagedRack() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("updateManagedRack", UcsRackDto.class);
+
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/racks/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UcsRackDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.managedRackPutPayload()),
+            UcsRackDto.class, UcsRackDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListServiceProfiles() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listServiceProfiles", UcsRackDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/logicservers HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + LogicServersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListServiceProfilesWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        FilterOptions options = FilterOptions.builder().startWith(1).limit(2).build();
+
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listServiceProfiles", UcsRackDto.class,
+                FilterOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(), options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/logicservers?startwith=1&limit=2 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + LogicServersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListOrganizations() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listOrganizations", UcsRackDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/organizations HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + OrganizationsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListOrganizationsWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        FilterOptions options = FilterOptions.builder().has("org").build();
+
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listOrganizations", UcsRackDto.class,
+                FilterOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(), options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/organizations?has=org HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + OrganizationsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListServiceProfileTemplates() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listServiceProfileTemplates", UcsRackDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/lstemplates HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + LogicServersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListServiceProfileTemplatesWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        FilterOptions options = FilterOptions.builder().ascendant(true).build();
+
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listServiceProfileTemplates", UcsRackDto.class,
+                FilterOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(), options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/lstemplates?asc=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + LogicServersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testAssociateLogicServer() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("associateLogicServer", UcsRackDto.class,
+                LogicServerDto.class, OrganizationDto.class, String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(),
+                InfrastructureResources.logicServerPut(),
+                InfrastructureResources.organizationPut(), "blade");
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/logicservers/associate?bladeDn=blade&org=org-root%2Forg-Finance&lsName=server HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testAssociateTemplate() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("associateTemplate", UcsRackDto.class,
+                LogicServerDto.class, OrganizationDto.class, String.class, String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(),
+                InfrastructureResources.logicServerPut(),
+                InfrastructureResources.organizationPut(), "newname", "blade");
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/logicservers/associatetemplate?newName=newname&bladeDn=blade&org=org-root%2Forg-Finance&lsName=server HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCloneAndAssociateLogicServer() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("cloneAndAssociateLogicServer",
+                UcsRackDto.class, LogicServerDto.class, OrganizationDto.class, String.class,
+                String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(),
+                InfrastructureResources.logicServerPut(),
+                InfrastructureResources.organizationPut(), "newname", "blade");
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/logicservers/assocclone?newName=newname&bladeDn=blade&org=org-root%2Forg-Finance&lsName=server HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDissociateLogicServer() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("dissociateLogicServer", UcsRackDto.class,
+                LogicServerDto.class);
+        GeneratedHttpRequest request =
+            processor
+                .createRequest(method, InfrastructureResources.managedRackPut(),
+                    InfrastructureResources.logicServerPut(),
+                    InfrastructureResources.organizationPut());
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/logicservers/dissociate?lsName=server HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCloneLogicServer() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("cloneLogicServer", UcsRackDto.class,
+                LogicServerDto.class, OrganizationDto.class, String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(),
+                InfrastructureResources.logicServerPut(),
+                InfrastructureResources.organizationPut(), "name");
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/logicservers/clone?newName=name&org=org-root%2Forg-Finance&lsName=server HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteLogicServer() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("deleteLogicServer", UcsRackDto.class,
+                LogicServerDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(),
+                InfrastructureResources.logicServerPut());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/logicservers/delete?lsName=server HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListFsms() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listFsms", UcsRackDto.class, String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.managedRackPut(), "dn");
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/fsm?dn=dn HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + FsmsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Remote Service **********************/
+
+    public void testListRemoteServices() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listRemoteServices", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/remoteservices HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RemoteServicesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateRemoteService() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("createRemoteService", DatacenterDto.class,
+                RemoteServiceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(),
+                InfrastructureResources.remoteServicePost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/remoteservices HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RemoteServiceDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request,
+            withHeader(InfrastructureResources.remoteServicePostPayload()), RemoteServiceDto.class,
+            RemoteServiceDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetRemoteService() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getRemoteService", DatacenterDto.class,
+                RemoteServiceType.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(),
+                RemoteServiceType.STORAGE_SYSTEM_MONITOR);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/remoteservices/storagesystemmonitor HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RemoteServiceDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateRemoteService() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("updateRemoteService", RemoteServiceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.remoteServicePut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/remoteservices/nodecollector HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + RemoteServiceDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.remoteServicePutPayload()),
+            RemoteServiceDto.class, RemoteServiceDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteRemoteService() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("deleteRemoteService", RemoteServiceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.remoteServicePut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/datacenters/1/remoteservices/nodecollector HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testIsAvailableRemoteService() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("isAvailable", RemoteServiceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.remoteServicePut());
+
+        String checkUri = InfrastructureResources.remoteServicePut().searchLink("check").getHref();
+        assertRequestLineEquals(request, String.format("GET %s HTTP/1.1", checkUri));
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTrueIf2xx.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnFalseIfNotAvailable.class);
+
+        checkFilters(request);
+    }
+
+    /*********************** Machine ***********************/
+
+    public void testDiscoverSingleMachineWithoutOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("discoverSingleMachine", DatacenterDto.class,
+                String.class, HypervisorType.class, String.class, String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "10.60.1.222",
+                HypervisorType.XENSERVER, "user", "pass");
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/discoversingle";
+        String query = "hypervisor=XENSERVER&ip=10.60.1.222&user=user&password=pass";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testDiscoverSingleMachineAllParams() throws SecurityException,
+        NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("discoverSingleMachine", DatacenterDto.class,
+                String.class, HypervisorType.class, String.class, String.class,
+                MachineOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "80.80.80.80",
+                HypervisorType.KVM, "user", "pass", MachineOptions.builder().port(8889).build());
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/discoversingle";
+        String query = "hypervisor=KVM&ip=80.80.80.80&user=user&password=pass&port=8889";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testDiscoverSingleMachineDefaultValues() throws SecurityException,
+        NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("discoverSingleMachine", DatacenterDto.class,
+                String.class, HypervisorType.class, String.class, String.class,
+                MachineOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "80.80.80.80",
+                HypervisorType.KVM, "user", "pass", MachineOptions.builder().build());
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/discoversingle";
+        String query = "hypervisor=KVM&ip=80.80.80.80&user=user&password=pass";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testDiscoverMultipleMachinesWithoutOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("discoverMultipleMachines", DatacenterDto.class,
+                String.class, String.class, HypervisorType.class, String.class, String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "10.60.1.222",
+                "10.60.1.250", HypervisorType.XENSERVER, "user", "pass");
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/discovermultiple";
+        String query =
+            "password=pass&ipTo=10.60.1.250&ipFrom=10.60.1.222&hypervisor=XENSERVER&user=user";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachinesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testDiscoverMultipleMachinesAllParams() throws SecurityException,
+        NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("discoverMultipleMachines", DatacenterDto.class,
+                String.class, String.class, HypervisorType.class, String.class, String.class,
+                MachineOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "80.80.80.80",
+                "80.80.80.86", HypervisorType.KVM, "user", "pass",
+                MachineOptions.builder().port(8889).build());
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/discovermultiple";
+        String query =
+            "password=pass&ipTo=80.80.80.86&ipFrom=80.80.80.80&hypervisor=KVM&user=user&port=8889";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachinesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testCheckMachineStateWithoutOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("checkMachineState", DatacenterDto.class,
+                String.class, HypervisorType.class, String.class, String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "10.60.1.222",
+                HypervisorType.XENSERVER, "user", "pass");
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/checkmachinestate";
+        String query = "hypervisor=XENSERVER&ip=10.60.1.222&user=user&password=pass";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineStateDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testCheckMachineStateAllParams() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("checkMachineState", DatacenterDto.class,
+                String.class, HypervisorType.class, String.class, String.class,
+                MachineOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "10.60.1.222",
+                HypervisorType.XENSERVER, "user", "pass", MachineOptions.builder().port(8889)
+                    .build());
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/checkmachinestate";
+        String query = "hypervisor=XENSERVER&ip=10.60.1.222&user=user&password=pass&port=8889";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineStateDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testCheckMachineIpmiStateWithoutOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("checkMachineIpmiState", DatacenterDto.class,
+                String.class, String.class, String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "10.60.1.222",
+                "user", "pass");
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/checkmachineipmistate";
+        String query = "user=user&ip=10.60.1.222&password=pass";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineIpmiStateDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testCheckMachineIpmiStateWithALLOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("checkMachineIpmiState", DatacenterDto.class,
+                String.class, String.class, String.class, IpmiOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), "10.60.1.222",
+                "user", "pass", IpmiOptions.builder().port(8889).build());
+
+        String baseUrl = "http://localhost/api/admin/datacenters/1/action/checkmachineipmistate";
+        String query = "user=user&ip=10.60.1.222&password=pass&port=8889";
+        String expectedRequest = String.format("GET %s?%s HTTP/1.1", baseUrl, query);
+
+        assertRequestLineEquals(request, expectedRequest);
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineIpmiStateDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnAbiquoExceptionOnNotFoundOr4xx.class);
+
+        checkFilters(request);
+    }
+
+    public void testListMachines() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("listMachines", RackDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.rackPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/machines HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachinesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetMachine() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getMachine", RackDto.class, Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.rackPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/machines/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testCheckMachineState() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("checkMachineState", MachineDto.class,
+                boolean.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut(), true);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/checkstate?sync=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineStateDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCheckMachineIpmiState() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("checkMachineIpmiState", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/checkipmistate HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineIpmiStateDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateMachine() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class
+                .getMethod("createMachine", RackDto.class, MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.rackPut(),
+                InfrastructureResources.machinePost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/machines HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.machinePostPayload()),
+            MachineDto.class, MachineDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateMachine() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("updateMachine", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/racks/1/machines/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.machinePutPayload()),
+            MachineDto.class, MachineDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteMachine() throws SecurityException, NoSuchMethodException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("deleteMachine", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/datacenters/1/racks/1/machines/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testReserveMachine() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("reserveMachine", EnterpriseDto.class,
+                MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut(),
+                InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/enterprises/1/reservedmachines HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + MachineDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.machinePutPayload()),
+            MachineDto.class, MachineDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCancelReservation() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("cancelReservation", EnterpriseDto.class,
+                MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, EnterpriseResources.enterprisePut(),
+                InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/enterprises/1/reservedmachines/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVirtualMachinesByMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        MachineOptions options = MachineOptions.builder().sync(true).build();
+
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listVirtualMachinesByMachine",
+                MachineDto.class, MachineOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut(), options);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/machines/1/virtualmachines?sync=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachinesWithNodeExtendedDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetVirtualMachineByMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getVirtualMachine", MachineDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/machines/1/virtualmachines/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineWithNodeExtendedDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    /*********************** Blade ***********************/
+
+    public void testPowerOff() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("powerOff", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/poweroff HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testPowerOn() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("powerOn", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/poweron HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetLogicServer() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("getLogicServer", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/machines/1/logicserver HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + LogicServerDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testLedOn() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("ledOn", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/ledon HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testLedOff() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("ledOff", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/racks/1/machines/1/action/ledoff HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetLocatorLed() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("getLocatorLed", MachineDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.machinePut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/racks/1/machines/1/led HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + BladeLocatorLedDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Storage Device ***********************/
+
+    public void testListStorageDevices() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listStorageDevices", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/devices HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StorageDevicesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListSupportedStorageDevices() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listSupportedStorageDevices",
+                DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/devices/action/supported HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + StorageDevicesMetadataDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateStorageDevice() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("createStorageDevice", DatacenterDto.class,
+                StorageDeviceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(),
+                InfrastructureResources.storageDevicePost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/storage/devices HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StorageDeviceDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request,
+            withHeader(InfrastructureResources.storageDevicePostPayload()), StorageDeviceDto.class,
+            StorageDeviceDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteStorageDevice() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("deleteStorageDevice", StorageDeviceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storageDevicePut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/datacenters/1/storage/devices/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateStorageDevice() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("updateStorageDevice", StorageDeviceDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storageDevicePut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/storage/devices/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StorageDeviceDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.storageDevicePutPayload()),
+            StorageDeviceDto.class, StorageDeviceDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetStorageDevice() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getStorageDevice", DatacenterDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/devices/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StorageDeviceDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    /*********************** Tier ***********************/
+
+    public void testListTiers() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("listTiers", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/tiers HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TiersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateTier() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("updateTier", TierDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.tierPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/storage/tiers/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TierDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.tierPutPayload()),
+            TierDto.class, TierDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetTier() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getTier", DatacenterDto.class, Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/tiers/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TierDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    /*********************** StoragePool ***********************/
+
+    public void testListSyncStoragePools() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listStoragePools", StorageDeviceDto.class,
+                StoragePoolOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storageDevicePut(),
+                StoragePoolOptions.builder().sync(true).build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/devices/1/pools?sync=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StoragePoolsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListStoragePoolsFromTier() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("listStoragePools", TierDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.tierPut(), StoragePoolOptions
+                .builder().sync(true).build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/tiers/1/pools HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StoragePoolsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListStoragePoolsNoParams() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listStoragePools", StorageDeviceDto.class,
+                StoragePoolOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storageDevicePut(),
+                StoragePoolOptions.builder().build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/devices/1/pools HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StoragePoolsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreateStoragePool() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("createStoragePool", StorageDeviceDto.class,
+                StoragePoolDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storageDevicePut(),
+                InfrastructureResources.storagePoolPost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/storage/devices/1/pools HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StoragePoolDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.storagePoolPostPayload()),
+            StoragePoolDto.class, StoragePoolDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateStoragePool() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("updateStoragePool", StoragePoolDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storagePoolPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/storage/devices/1/pools/tururututu HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StoragePoolDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(InfrastructureResources.storagePoolPutPayload()),
+            StoragePoolDto.class, StoragePoolDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteStoragePool() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("deleteStoragePool", StoragePoolDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storagePoolPut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/datacenters/1/storage/devices/1/pools/tururututu HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetStoragePool() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getStoragePool", StorageDeviceDto.class,
+                String.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storageDevicePut(),
+                InfrastructureResources.storagePoolPut().getIdStorage());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/storage/devices/1/pools/tururututu HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StoragePoolDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testRefreshStoragePool() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("refreshStoragePool", StoragePoolDto.class,
+                StoragePoolOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.storagePoolPut(),
+                StoragePoolOptions.builder().sync(true).build());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/datacenters/1/storage/devices/1/pools/tururututu?sync=true HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + StoragePoolDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
+
+        checkFilters(request);
+    }
+
+    /*********************** Network ***********************/
+
+    public void testListNetworks() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = InfrastructureAsyncApi.class.getMethod("listNetworks", DatacenterDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/network HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworksDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListNetworksWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        NetworkOptions options = NetworkOptions.builder().type(NetworkType.PUBLIC).build();
+
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listNetworks", DatacenterDto.class,
+                NetworkOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/network?type=PUBLIC HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworksDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetNetworks() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class
+                .getMethod("getNetwork", DatacenterDto.class, Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/network/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworkDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testCreateNetwork() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("createNetwork", DatacenterDto.class,
+                VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(),
+                NetworkResources.vlanPost());
+
+        assertRequestLineEquals(request,
+            "POST http://localhost/api/admin/datacenters/1/network HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworkDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(NetworkResources.vlanNetworkPostPayload()),
+            VLANNetworkDto.class, VLANNetworkDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateNetwork() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("updateNetwork", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.publicNetworkPut());
+
+        assertRequestLineEquals(request,
+            "PUT http://localhost/api/admin/datacenters/1/network/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VLANNetworkDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(NetworkResources.publicNetworkPutPayload()),
+            VLANNetworkDto.class, VLANNetworkDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteNetwork() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("deleteNetwork", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.publicNetworkPut());
+
+        assertRequestLineEquals(request,
+            "DELETE http://localhost/api/admin/datacenters/1/network/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCheckTagAvailability() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("checkTagAvailability", DatacenterDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, InfrastructureResources.datacenterPut(), 2);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/network/action/checkavailability?tag=2 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + VlanTagAvailabilityDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
+
+        checkFilters(request);
+    }
+
+    /*********************** Network IPs ***********************/
+
+    public void testListPublicIps() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listPublicIps", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.publicNetworkPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/network/1/ips HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PublicIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListPublicIpsWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        IpOptions options = IpOptions.builder().startWith(10).build();
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listPublicIps", VLANNetworkDto.class,
+                IpOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.publicNetworkPut(), options);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/network/1/ips?startwith=10 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PublicIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetPublicIp() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getPublicIp", VLANNetworkDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.publicNetworkPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/datacenters/1/network/1/ips/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + PublicIpDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListExternalIps() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listExternalIps", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.externalNetworkPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/limits/1/externalnetworks/1/ips HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + ExternalIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListExternalIpsWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        IpOptions options = IpOptions.builder().startWith(10).build();
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listExternalIps", VLANNetworkDto.class,
+                IpOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.externalNetworkPut(), options);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/limits/1/externalnetworks/1/ips?startwith=10 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + ExternalIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetExternalIp() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getExternalIp", VLANNetworkDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.externalNetworkPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/limits/1/externalnetworks/1/ips/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + ExternalIpDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListUnmanagedIps() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listUnmanagedIps", VLANNetworkDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.unmanagedNetworkPut());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/limits/1/externalnetworks/1/ips HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UnmanagedIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListUnmanagedIpsWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        IpOptions options = IpOptions.builder().startWith(10).build();
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("listUnmanagedIps", VLANNetworkDto.class,
+                IpOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.unmanagedNetworkPut(), options);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/limits/1/externalnetworks/1/ips?startwith=10 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UnmanagedIpsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetUnmanagedIp() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            InfrastructureAsyncApi.class.getMethod("getUnmanagedIp", VLANNetworkDto.class,
+                Integer.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, NetworkResources.externalNetworkPut(), 1);
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/limits/1/externalnetworks/1/ips/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + UnmanagedIpDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<InfrastructureAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<InfrastructureAsyncApi>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/PricingAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/PricingAsyncApiTest.java
new file mode 100644
index 0000000..3e0f6a0
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/PricingAsyncApiTest.java
@@ -0,0 +1,145 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.abiquo.domain.PricingResources;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.http.functions.ReleasePayloadAndReturn;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.pricing.CurrenciesDto;
+import com.abiquo.server.core.pricing.CurrencyDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code PricingAsyncApi}.
+ * 
+ * @author Ignasi Barrera
+ * @author Susana Acedo
+ */
+@Test(groups = "unit", singleThreaded = true, testName = "PricingAsyncApiTest")
+public class PricingAsyncApiTest extends BaseAbiquoAsyncApiTest<PricingAsyncApi>
+{
+
+    /*********************** Currency ***********************/
+
+    public void testListCurrencies() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = PricingAsyncApi.class.getMethod("listCurrencies");
+        GeneratedHttpRequest request = processor.createRequest(method);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/config/currencies HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + CurrenciesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetCurrency() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = PricingAsyncApi.class.getMethod("getCurrency", Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1);
+
+        assertRequestLineEquals(request, "GET http://localhost/api/config/currencies/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + CurrencyDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    @Test(enabled = false) //TODO: fails
+    public void testCreateCurrency() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = PricingAsyncApi.class.getMethod("createCurrency", CurrencyDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, PricingResources.currencyPost());
+
+        assertRequestLineEquals(request, "POST http://localhost/api/config/currencies HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + CurrencyDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(PricingResources.currencyPostPayload()),
+            CurrencyDto.class, CurrencyDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+    
+    @Test(enabled = false) //TODO: fails
+    public void testUpdateCurrency() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method = PricingAsyncApi.class.getMethod("updateCurrency", CurrencyDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, PricingResources.currencyPut());
+
+        assertRequestLineEquals(request, "PUT http://localhost/api/config/currencies/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + CurrencyDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, withHeader(PricingResources.currencyPutPayload()),
+            CurrencyDto.class, CurrencyDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteCurrency() throws SecurityException, NoSuchMethodException
+    {
+        Method method = PricingAsyncApi.class.getMethod("deleteCurrency", CurrencyDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, PricingResources.currencyPut());
+
+        assertRequestLineEquals(request, "DELETE http://localhost/api/config/currencies/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<PricingAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<PricingAsyncApi>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/TaskAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/TaskAsyncApiTest.java
new file mode 100644
index 0000000..906a851
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/TaskAsyncApiTest.java
@@ -0,0 +1,145 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.abiquo.domain.CloudResources;
+import org.jclouds.abiquo.domain.TemplateResources;
+import org.jclouds.abiquo.functions.ReturnNullOn303;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.abiquo.server.core.task.TaskDto;
+import com.abiquo.server.core.task.TasksDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code TaskAsyncApi}
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "TaskAsyncApiTest")
+public class TaskAsyncApiTest extends BaseAbiquoAsyncApiTest<TaskAsyncApi>
+{
+    /*********************** Task ***********************/
+
+    public void testGetTaskVirtualMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = TaskAsyncApi.class.getMethod("getTask", RESTLink.class);
+        GeneratedHttpRequest request =
+            processor
+                .createRequest(
+                    method,
+                    new RESTLink("task",
+                        "http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/tasks/169f1877-5f17-4f62-9563-974001295c54"));
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/tasks/169f1877-5f17-4f62-9563-974001295c54 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TaskDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOn303.class);
+
+        checkFilters(request);
+    }
+
+    public void testListTasksVirtualMachine() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method = TaskAsyncApi.class.getMethod("listTasks", SingleResourceTransportDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, CloudResources.virtualMachinePut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/tasks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TasksDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetTaskVirtualMachineTemplate() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method = TaskAsyncApi.class.getMethod("getTask", RESTLink.class);
+        GeneratedHttpRequest request =
+            processor
+                .createRequest(
+                    method,
+                    new RESTLink("task",
+                        "http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/tasks/169f1877-5f17-4f62-9563-974001295c54"));
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/tasks/169f1877-5f17-4f62-9563-974001295c54 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TaskDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOn303.class);
+
+        checkFilters(request);
+    }
+
+    public void testListTasksVirtualMachineTemplate() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method = TaskAsyncApi.class.getMethod("listTasks", SingleResourceTransportDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, TemplateResources.virtualMachineTemplatePut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/tasks HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + TasksDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<TaskAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<TaskAsyncApi>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/features/VirtualMachineTemplateAsyncApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/VirtualMachineTemplateAsyncApiTest.java
new file mode 100644
index 0000000..b77477a
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/features/VirtualMachineTemplateAsyncApiTest.java
@@ -0,0 +1,304 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.features;
+
+import static org.jclouds.abiquo.domain.DomainUtils.withHeader;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.abiquo.domain.TemplateResources;
+import org.jclouds.abiquo.domain.cloud.options.ConversionOptions;
+import org.jclouds.abiquo.domain.cloud.options.VirtualMachineTemplateOptions;
+import org.jclouds.abiquo.functions.ReturnTaskReferenceOrNull;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
+import org.jclouds.http.functions.ReleasePayloadAndReturn;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.ConversionState;
+import com.abiquo.model.enumerator.DiskFormatType;
+import com.abiquo.model.enumerator.HypervisorType;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.appslibrary.ConversionDto;
+import com.abiquo.server.core.appslibrary.ConversionsDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatePersistentDto;
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplatesDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code VirtualMachineTemplateAsyncApi}
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "VirtualMachineTemplateAsyncApiTest")
+public class VirtualMachineTemplateAsyncApiTest extends
+    BaseAbiquoAsyncApiTest<VirtualMachineTemplateAsyncApi>
+{
+    /*********************** Virtual Machine Template ***********************/
+
+    public void testListVirtualMachineTemplates() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("listVirtualMachineTemplates",
+                Integer.class, Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1, 1);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineTemplatesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListVirtualMachineTemplatesWithOptions() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("listVirtualMachineTemplates",
+                Integer.class, Integer.class, VirtualMachineTemplateOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, 1, 1, VirtualMachineTemplateOptions.builder()
+                .hypervisorType(HypervisorType.XENSERVER).categoryName("Firewalls").build());
+
+        assertRequestLineEquals(request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates"
+                + "?hypervisorTypeName=XENSERVER&categoryName=Firewalls HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineTemplatesDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetVirtualMachineTemplate() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("getVirtualMachineTemplate",
+                Integer.class, Integer.class, Integer.class);
+        GeneratedHttpRequest request = processor.createRequest(method, 1, 1, 1);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineTemplateDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    public void testUpdateVirtualMachineTemplate() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("updateVirtualMachineTemplate",
+                VirtualMachineTemplateDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, TemplateResources.virtualMachineTemplatePut());
+
+        assertRequestLineEquals(
+            request,
+            "PUT http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: "
+            + VirtualMachineTemplateDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request,
+            withHeader(TemplateResources.virtualMachineTemplatePutPayload()),
+            VirtualMachineTemplateDto.class, VirtualMachineTemplateDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testDeleteVirtualMachineTemplate() throws SecurityException, NoSuchMethodException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("deleteVirtualMachineTemplate",
+                VirtualMachineTemplateDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, TemplateResources.virtualMachineTemplatePut());
+
+        assertRequestLineEquals(
+            request,
+            "DELETE http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1 HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testCreatePersistentVirtualMachineTemplate() throws SecurityException,
+        NoSuchMethodException, IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod(
+                "createPersistentVirtualMachineTemplate", Integer.class, Integer.class,
+                VirtualMachineTemplatePersistentDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, 1, 1, TemplateResources.persistentData());
+
+        assertRequestLineEquals(
+            request,
+            "POST http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(TemplateResources.persistentPayload()),
+            VirtualMachineTemplatePersistentDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    /*********************** Conversions ***********************/
+
+    public void testRequestConversion() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("requestConversion",
+                VirtualMachineTemplateDto.class, DiskFormatType.class, ConversionDto.class);
+
+        GeneratedHttpRequest request =
+            processor.createRequest(method, TemplateResources.virtualMachineTemplatePut(),
+                DiskFormatType.VMDK_STREAM_OPTIMIZED, TemplateResources.conversionPut());
+
+        assertRequestLineEquals(
+            request,
+            "PUT http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/conversions/VMDK_STREAM_OPTIMIZED HTTP/1.1");
+
+        assertNonPayloadHeadersEqual(request, "Accept: " + AcceptedRequestDto.BASE_MEDIA_TYPE
+            + "\n");
+        assertPayloadEquals(request, withHeader(TemplateResources.conversionPutPlayload()),
+            ConversionDto.BASE_MEDIA_TYPE, false);
+
+        assertResponseParserClassEquals(method, request, ReturnTaskReferenceOrNull.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListConversions() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("listConversions",
+                VirtualMachineTemplateDto.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, TemplateResources.virtualMachineTemplatePut());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/conversions HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + ConversionsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testListConversionsWithOptions() throws SecurityException, NoSuchMethodException,
+        IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("listConversions",
+                VirtualMachineTemplateDto.class, ConversionOptions.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, TemplateResources.virtualMachineTemplatePut(),
+                ConversionOptions.builder().hypervisorType(HypervisorType.XENSERVER)
+                    .conversionState(ConversionState.FINISHED).build());
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/conversions"
+                + "?hypervisor=XENSERVER&state=FINISHED HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + ConversionsDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, null);
+
+        checkFilters(request);
+    }
+
+    public void testGetConversion() throws SecurityException, NoSuchMethodException, IOException
+    {
+        Method method =
+            VirtualMachineTemplateAsyncApi.class.getMethod("getConversion",
+                VirtualMachineTemplateDto.class, DiskFormatType.class);
+        GeneratedHttpRequest request =
+            processor.createRequest(method, TemplateResources.virtualMachineTemplatePut(),
+                DiskFormatType.RAW);
+
+        assertRequestLineEquals(
+            request,
+            "GET http://localhost/api/admin/enterprises/1/datacenterrepositories/1/virtualmachinetemplates/1/conversions/RAW HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + ConversionDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, ParseXMLWithJAXB.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<VirtualMachineTemplateAsyncApi>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<VirtualMachineTemplateAsyncApi>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/AppendApiVersionToAbiquoMimeTypeTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/AppendApiVersionToAbiquoMimeTypeTest.java
new file mode 100644
index 0000000..115e551
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/AppendApiVersionToAbiquoMimeTypeTest.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link AppendApiVersionToAbiquoMimeType} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AppendApiVersionToAbiquoMimeTypeTest")
+public class AppendApiVersionToAbiquoMimeTypeTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testApplyWithNullInput()
+    {
+        Function<String, String> function =
+            new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION);
+        function.apply(null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testApplyWithInvalidMediaType()
+    {
+        Function<String, String> function =
+            new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION);
+        function.apply("foo");
+    }
+
+    public void testApplyToStandardMediaType()
+    {
+        Function<String, String> function =
+            new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION);
+        assertEquals(function.apply("application/xml"), "application/xml");
+    }
+
+    public void testApplyToAbiquoMediaTypeWithVersion()
+    {
+        Function<String, String> function =
+            new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION);
+        assertEquals(function.apply("application/vnd.abiquo.datacenters+xml;version=1.8.5"),
+            "application/vnd.abiquo.datacenters+xml;version=1.8.5");
+    }
+
+    public void testApplyToAbiquoMediaTypeWithoutVersion()
+    {
+        Function<String, String> function =
+            new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION);
+        assertEquals(function.apply("application/vnd.abiquo.datacenters+xml"),
+            "application/vnd.abiquo.datacenters+xml;version=" + AbiquoAsyncApi.API_VERSION);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnAbiquoExceptionOnNotFoundOr4xxTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnAbiquoExceptionOnNotFoundOr4xxTest.java
new file mode 100644
index 0000000..5f3b6eb
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnAbiquoExceptionOnNotFoundOr4xxTest.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.transport.error.ErrorsDto;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ReturnAbiquoExceptionOnNotFoundOr4xx} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "ReturnAbiquoExceptionOnNotFoundOr4xxTest")
+public class ReturnAbiquoExceptionOnNotFoundOr4xxTest
+{
+    public void testReturnOriginalExceptionIfNotResourceNotFound()
+    {
+        Function<Exception, Object> function = new ReturnAbiquoExceptionOnNotFoundOr4xx();
+        RuntimeException exception = new RuntimeException();
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+    }
+
+    public void testReturnOriginalExceptionIfNotAbiquoException()
+    {
+        Function<Exception, Object> function = new ReturnAbiquoExceptionOnNotFoundOr4xx();
+        ResourceNotFoundException exception = new ResourceNotFoundException();
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+    }
+
+    public void testReturnAbiquoException()
+    {
+        Function<Exception, Object> function = new ReturnAbiquoExceptionOnNotFoundOr4xx();
+        AbiquoException abiquoException = new AbiquoException(Status.NOT_FOUND, new ErrorsDto());
+        ResourceNotFoundException exception = new ResourceNotFoundException(abiquoException);
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, abiquoException);
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnFalseIfNotAvailableTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnFalseIfNotAvailableTest.java
new file mode 100644
index 0000000..423c095
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnFalseIfNotAvailableTest.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ReturnFalseIfNotAvailable} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "ReturnFalseIfNotAvailableTest")
+public class ReturnFalseIfNotAvailableTest
+{
+    public void testReturnOriginalExceptionIfUnknownException()
+    {
+        Function<Exception, Object> function = new ReturnFalseIfNotAvailable();
+        RuntimeException exception = new RuntimeException();
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+    }
+
+    public void testReturnFalseIf5xx()
+    {
+        Function<Exception, Object> function = new ReturnFalseIfNotAvailable();
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+        HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
+
+        // Status code is called twice
+        expect(response.getStatusCode()).andReturn(503);
+        expect(response.getStatusCode()).andReturn(503);
+        // Get response gets called twice
+        expect(exception.getResponse()).andReturn(response);
+        expect(exception.getResponse()).andReturn(response);
+        // Get cause is called to determine the root cause
+        expect(exception.getCause()).andReturn(null);
+
+        replay(response);
+        replay(exception);
+
+        assertEquals(function.apply(exception), false);
+
+        verify(response);
+        verify(exception);
+    }
+
+    public void testReturnExceptionIfNot5xx()
+    {
+        Function<Exception, Object> function = new ReturnFalseIfNotAvailable();
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+        HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
+
+        // Status code is called twice
+        expect(response.getStatusCode()).andReturn(600);
+        expect(response.getStatusCode()).andReturn(600);
+        // Get response gets called twice
+        expect(exception.getResponse()).andReturn(response);
+        expect(exception.getResponse()).andReturn(response);
+        // Get cause is called to determine the root cause
+        expect(exception.getCause()).andReturn(null);
+
+        replay(response);
+        replay(exception);
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+
+        verify(response);
+        verify(exception);
+    }
+
+    public void testReturnFalseIfResourceNotFound()
+    {
+        Function<Exception, Object> function = new ReturnFalseIfNotAvailable();
+        ResourceNotFoundException exception = new ResourceNotFoundException();
+
+        assertEquals(function.apply(exception), false);
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnFalseOn5xxTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnFalseOn5xxTest.java
new file mode 100644
index 0000000..8cab916
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnFalseOn5xxTest.java
@@ -0,0 +1,111 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ReturnFalseOn5xx} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "ReturnFalseOn5xxTest")
+public class ReturnFalseOn5xxTest
+{
+    public void testReturnOriginalExceptionIfNotHttpResponseException()
+    {
+        Function<Exception, Object> function = new ReturnFalseOn5xx();
+        RuntimeException exception = new RuntimeException();
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+    }
+
+    public void testReturnFalseIf5xx()
+    {
+        Function<Exception, Object> function = new ReturnFalseOn5xx();
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+        HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
+
+        // Status code is called twice
+        expect(response.getStatusCode()).andReturn(503);
+        expect(response.getStatusCode()).andReturn(503);
+        // Get response gets called twice
+        expect(exception.getResponse()).andReturn(response);
+        expect(exception.getResponse()).andReturn(response);
+        // Get cause is called to determine the root cause
+        expect(exception.getCause()).andReturn(null);
+
+        replay(response);
+        replay(exception);
+
+        assertEquals(function.apply(exception), false);
+
+        verify(response);
+        verify(exception);
+    }
+
+    public void testReturnExceptionIfNot5xx()
+    {
+        Function<Exception, Object> function = new ReturnFalseOn5xx();
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+        HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
+
+        // Status code is called twice
+        expect(response.getStatusCode()).andReturn(600);
+        expect(response.getStatusCode()).andReturn(600);
+        // Get response gets called twice
+        expect(exception.getResponse()).andReturn(response);
+        expect(exception.getResponse()).andReturn(response);
+        // Get cause is called to determine the root cause
+        expect(exception.getCause()).andReturn(null);
+
+        replay(response);
+        replay(exception);
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+
+        verify(response);
+        verify(exception);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnNullOn303Test.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnNullOn303Test.java
new file mode 100644
index 0000000..c79f534
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnNullOn303Test.java
@@ -0,0 +1,110 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+import org.easymock.EasyMock;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ReturnNullOn303} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "ReturnNullOn303Test")
+public class ReturnNullOn303Test
+{
+    public void testReturnOriginalExceptionIfNotHttpResponseException()
+    {
+        Function<Exception, Object> function = new ReturnNullOn303();
+        RuntimeException exception = new RuntimeException();
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+    }
+
+    public void testReturnNullIf303()
+    {
+        Function<Exception, Object> function = new ReturnNullOn303();
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+        HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
+
+        // Status code is called once
+        expect(response.getStatusCode()).andReturn(303);
+        // Get response gets called twice
+        expect(exception.getResponse()).andReturn(response);
+        expect(exception.getResponse()).andReturn(response);
+        // Get cause is called to determine the root cause
+        expect(exception.getCause()).andReturn(null);
+
+        replay(response);
+        replay(exception);
+
+        assertNull(function.apply(exception));
+
+        verify(response);
+        verify(exception);
+    }
+
+    public void testReturnExceptionIfNot303()
+    {
+        Function<Exception, Object> function = new ReturnNullOn303();
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+        HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
+
+        // Status code is called once
+        expect(response.getStatusCode()).andReturn(600);
+        // Get response gets called twice
+        expect(exception.getResponse()).andReturn(response);
+        expect(exception.getResponse()).andReturn(response);
+        // Get cause is called to determine the root cause
+        expect(exception.getCause()).andReturn(null);
+
+        replay(response);
+        replay(exception);
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+
+        verify(response);
+        verify(exception);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnTaskReferenceOrNullTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnTaskReferenceOrNullTest.java
new file mode 100644
index 0000000..0fb2db3
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/ReturnTaskReferenceOrNullTest.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.easymock.EasyMock;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Unit tests for the {@link ReturnTaskReferenceOrNull} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "ReturnTaskReferenceOrNullTest")
+public class ReturnTaskReferenceOrNullTest
+{
+    public void testReturnNullIfNoContent()
+    {
+        Function<HttpResponse, AcceptedRequestDto<String>> function =
+            new ReturnTaskReferenceOrNull(new JAXBParser("false"), createTypeLiteral());
+
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+
+        expect(response.getStatusCode()).andReturn(Status.NO_CONTENT.getStatusCode());
+        expect(response.getPayload()).andReturn(null);
+
+        replay(response);
+
+        assertNull(function.apply(response));
+
+        verify(response);
+    }
+
+    public void testReturnTaskIfAccepted() throws IOException
+    {
+        JAXBParser parser = new JAXBParser("false");
+        AcceptedRequestDto< ? > task = new AcceptedRequestDto<String>();
+        Payload payload = Payloads.newPayload(parser.toXML(task));
+
+        Function<HttpResponse, AcceptedRequestDto<String>> function =
+            new ReturnTaskReferenceOrNull(parser, createTypeLiteral());
+
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+
+        expect(response.getStatusCode()).andReturn(Status.ACCEPTED.getStatusCode());
+        // Get payload is called three times: one to deserialize it, and twice to release it
+        expect(response.getPayload()).andReturn(payload);
+        expect(response.getPayload()).andReturn(payload);
+        expect(response.getPayload()).andReturn(payload);
+
+        replay(response);
+
+        assertTrue(function.apply(response) instanceof AcceptedRequestDto);
+
+        verify(response);
+    }
+
+    private static TypeLiteral<AcceptedRequestDto<String>> createTypeLiteral()
+    {
+        return new TypeLiteral<AcceptedRequestDto<String>>()
+        {
+        };
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/cloud/ReturnMovedVolumeTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/cloud/ReturnMovedVolumeTest.java
new file mode 100644
index 0000000..a86b230
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/cloud/ReturnMovedVolumeTest.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.cloud;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.easymock.EasyMock;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.xml.internal.JAXBParser;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.storage.MovedVolumeDto;
+import com.abiquo.server.core.infrastructure.storage.VolumeManagementDto;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Unit tests for the {@link ReturnMovedVolume} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "ReturnMovedVolumeTest")
+public class ReturnMovedVolumeTest
+{
+    public void testReturnOriginalExceptionIfNotHttpResponseException()
+    {
+        Function<Exception, VolumeManagementDto> function =
+            new ReturnMovedVolume(new ReturnMoveVolumeReference(new JAXBParser("false"),
+                TypeLiteral.get(MovedVolumeDto.class)));
+
+        RuntimeException exception = new RuntimeException();
+
+        try
+        {
+            function.apply(exception);
+        }
+        catch (Exception ex)
+        {
+            assertEquals(ex, exception);
+        }
+    }
+
+    public void testReturnVolume() throws IOException
+    {
+        JAXBParser xmlParser = new JAXBParser("false");
+        Function<Exception, VolumeManagementDto> function =
+            new ReturnMovedVolume(new ReturnMoveVolumeReference(new JAXBParser("false"),
+                TypeLiteral.get(MovedVolumeDto.class)));
+
+        VolumeManagementDto volume = new VolumeManagementDto();
+        volume.setName("Test volume");
+        MovedVolumeDto movedRef = new MovedVolumeDto();
+        movedRef.setVolume(volume);
+
+        HttpResponse response = EasyMock.createMock(HttpResponse.class);
+        HttpResponseException exception = EasyMock.createMock(HttpResponseException.class);
+        Payload payload = Payloads.newPayload(xmlParser.toXML(movedRef));
+
+        // Status code is called once
+        expect(response.getStatusCode()).andReturn(Status.MOVED_PERMANENTLY.getStatusCode());
+        // Get response gets called twice
+        expect(exception.getResponse()).andReturn(response);
+        expect(exception.getResponse()).andReturn(response);
+        // Get payload is called three times: one to deserialize it, and twice to release it
+        expect(response.getPayload()).andReturn(payload);
+        expect(response.getPayload()).andReturn(payload);
+        expect(response.getPayload()).andReturn(payload);
+        // Get cause is called to determine the root cause
+        expect(exception.getCause()).andReturn(null);
+
+        replay(response);
+        replay(exception);
+
+        function.apply(exception);
+
+        verify(response);
+        verify(exception);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/enterprise/ParseEnterpriseIdTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/enterprise/ParseEnterpriseIdTest.java
new file mode 100644
index 0000000..2822fae
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/enterprise/ParseEnterpriseIdTest.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.enterprise;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.enterprise.EnterpriseDto;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ParseEnterpriseId} function.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "ParseEnterpriseIdTest")
+public class ParseEnterpriseIdTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        Function<Object, String> parser = new ParseEnterpriseId();
+        parser.apply(null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidInputType()
+    {
+        Function<Object, String> parser = new ParseEnterpriseId();
+        parser.apply(new Object());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidId()
+    {
+        Function<Object, String> parser = new ParseEnterpriseId();
+        parser.apply(new EnterpriseDto());
+    }
+
+    public void testValidId()
+    {
+        Function<Object, String> parser = new ParseEnterpriseId();
+
+        EnterpriseDto enterprise = new EnterpriseDto();
+        enterprise.setId(5);
+        assertEquals(parser.apply(enterprise), "5");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseDatacenterIdTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseDatacenterIdTest.java
new file mode 100644
index 0000000..bf93734
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseDatacenterIdTest.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.DatacenterDto;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ParseDatacenterId} function.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "ParseDatacenterIdTest")
+public class ParseDatacenterIdTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        Function<Object, String> parser = new ParseDatacenterId();
+        parser.apply(null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidInputType()
+    {
+        Function<Object, String> parser = new ParseDatacenterId();
+        parser.apply(new Object());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidId()
+    {
+        Function<Object, String> parser = new ParseDatacenterId();
+        parser.apply(new DatacenterDto());
+    }
+
+    public void testValidId()
+    {
+        Function<Object, String> parser = new ParseDatacenterId();
+
+        DatacenterDto datacenter = new DatacenterDto();
+        datacenter.setId(5);
+        assertEquals(parser.apply(datacenter), "5");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseMachineIdTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseMachineIdTest.java
new file mode 100644
index 0000000..2d1a938
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseMachineIdTest.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.infrastructure.MachineDto;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ParseMachineId} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "ParseMachineIdTest")
+public class ParseMachineIdTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        Function<Object, String> parser = new ParseMachineId();
+        parser.apply(null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidInputType()
+    {
+        Function<Object, String> parser = new ParseMachineId();
+        parser.apply(new Object());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidId()
+    {
+        Function<Object, String> parser = new ParseMachineId();
+        parser.apply(new MachineDto());
+    }
+
+    public void testValidId()
+    {
+        Function<Object, String> parser = new ParseMachineId();
+
+        MachineDto machine = new MachineDto();
+        machine.setId(5);
+        assertEquals(parser.apply(machine), "5");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseRemoteServiceTypeTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseRemoteServiceTypeTest.java
new file mode 100644
index 0000000..828ae42
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/functions/infrastructure/ParseRemoteServiceTypeTest.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.functions.infrastructure;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.RemoteServiceType;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ParseRemoteServiceType} functions.
+ * 
+ * @author Francesc Montserrat
+ */
+@Test(groups = "unit", testName = "ParseRemoteServiceTypeTest")
+public class ParseRemoteServiceTypeTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullInput()
+    {
+        Function<Object, String> parser = new ParseRemoteServiceType();
+        parser.apply(null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testInvalidInputType()
+    {
+        Function<Object, String> parser = new ParseRemoteServiceType();
+        parser.apply(new Object());
+    }
+
+    public void testValidId()
+    {
+        Function<Object, String> parser = new ParseRemoteServiceType();
+        assertEquals(parser.apply(RemoteServiceType.BPM_SERVICE), "bpmservice");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AbiquoAuthenticationLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AbiquoAuthenticationLiveApiTest.java
new file mode 100644
index 0000000..e63697c
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AbiquoAuthenticationLiveApiTest.java
@@ -0,0 +1,199 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.http.filters;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.http.HttpUtils.releasePayload;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Properties;
+
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.HttpHeaders;
+
+import org.jclouds.ContextBuilder;
+import org.jclouds.abiquo.AbiquoApiMetadata;
+import org.jclouds.abiquo.AbiquoContext;
+import org.jclouds.abiquo.config.AbiquoProperties;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+import org.jclouds.rest.AuthorizationException;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.enterprise.UserDto;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Live tests for the {@link AbiquoAuthentication} filter.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "AbiquoAuthenticationLiveApiTest")
+public class AbiquoAuthenticationLiveApiTest
+{
+    private String identity;
+
+    private String credential;
+
+    private String endpoint;
+
+    @BeforeMethod
+    public void setupToken()
+    {
+        identity = checkNotNull(System.getProperty("test.abiquo.identity"), "test.abiquo.identity");
+        credential =
+            checkNotNull(System.getProperty("test.abiquo.credential"), "test.abiquo.credential");
+        endpoint = checkNotNull(System.getProperty("test.abiquo.endpoint"), "test.abiquo.endpoint");
+    }
+
+    @Test
+    public void testAuthenticateWithToken() throws IOException
+    {
+        String token = getAuthtenticationToken();
+
+        Properties props = new Properties();
+        props.setProperty(AbiquoProperties.CREDENTIAL_IS_TOKEN, "true");
+
+        // Create a new context that uses the generated token to perform the API calls
+        AbiquoContext tokenContext = ContextBuilder.newBuilder(new AbiquoApiMetadata()) //
+            .endpoint(endpoint) //
+            .credentials("token", token) //
+            .modules(ImmutableSet.<Module> of(new SLF4JLoggingModule())) //
+            .overrides(props) //
+            .build(AbiquoContext.class);
+
+        try
+        {
+            // Perform a call to get the logged user and verify the identity
+            UserDto user = tokenContext.getApiContext().getApi().getAdminApi().getCurrentUser();
+            assertNotNull(user);
+            assertEquals(user.getNick(), identity);
+        }
+        finally
+        {
+            if (tokenContext != null)
+            {
+                tokenContext.close();
+            }
+        }
+    }
+
+    @Test
+    public void testAuthenticateWithInvalidToken() throws IOException
+    {
+        String token = getAuthtenticationToken() + "INVALID";
+
+        Properties props = new Properties();
+        props.setProperty(AbiquoProperties.CREDENTIAL_IS_TOKEN, "true");
+
+        // Create a new context that uses the generated token to perform the API calls
+        AbiquoContext tokenContext = ContextBuilder.newBuilder(new AbiquoApiMetadata()) //
+            .endpoint(endpoint) //
+            .credentials("token", token) //
+            .modules(ImmutableSet.<Module> of(new SLF4JLoggingModule())) //
+            .overrides(props) //
+            .build(AbiquoContext.class);
+
+        // Perform a call to get the logged user. It should fail
+        try
+        {
+            tokenContext.getApiContext().getApi().getAdminApi().getCurrentUser();
+        }
+        catch (AuthorizationException ex)
+        {
+            // Test succeeded
+            return;
+        }
+        finally
+        {
+            if (tokenContext != null)
+            {
+                tokenContext.close();
+            }
+        }
+
+        fail("Token authentication should have failed");
+    }
+
+    private String getAuthtenticationToken() throws UnsupportedEncodingException
+    {
+        String token = null;
+
+        AbiquoContext context = ContextBuilder.newBuilder(new AbiquoApiMetadata()) //
+            .endpoint(endpoint) //
+            .credentials(identity, credential) //
+            .modules(ImmutableSet.<Module> of(new SLF4JLoggingModule())) //
+            .build(AbiquoContext.class);
+
+        try
+        {
+            // Create a request to authenticate to the API and generate the token
+            HttpRequest request =
+                HttpRequest.builder().method("GET").endpoint(URI.create(endpoint)).build();
+            String auth = AbiquoAuthentication.basicAuth(identity, credential);
+            request = request.toBuilder().replaceHeader(HttpHeaders.AUTHORIZATION, auth).build();
+
+            // Execute the request and read the generated token
+            HttpResponse response = context.utils().http().invoke(request);
+            assertEquals(response.getStatusCode(), 200);
+
+            token = readAuthenticationToken(response);
+            assertNotNull(token);
+
+            releasePayload(response);
+        }
+        finally
+        {
+            if (context != null)
+            {
+                context.close();
+            }
+        }
+
+        return token;
+    }
+
+    private String readAuthenticationToken(final HttpResponse response)
+    {
+        Collection<String> cookies = response.getHeaders().get(HttpHeaders.SET_COOKIE);
+        assertFalse(cookies.isEmpty());
+
+        for (String cookie : cookies)
+        {
+            Cookie c = Cookie.valueOf(cookie);
+            if (c.getName().equals(AbiquoAuthentication.AUTH_TOKEN_NAME))
+            {
+                return c.getValue();
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AbiquoAuthenticationTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AbiquoAuthenticationTest.java
new file mode 100644
index 0000000..2bfce5e
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AbiquoAuthenticationTest.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.http.filters;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
+import javax.ws.rs.core.HttpHeaders;
+
+import org.jclouds.http.HttpRequest;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link AbiquoAuthentication} filter.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AbiquoAuthenticationTest")
+public class AbiquoAuthenticationTest
+{
+
+    public void testBasicAuthentication() throws UnsupportedEncodingException,
+        NoSuchAlgorithmException, CertificateException
+    {
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).build();
+
+        AbiquoAuthentication filter = new AbiquoAuthentication("identity", "credential", "false");
+        HttpRequest filtered = filter.filter(request);
+        HttpRequest expected =
+            request
+                .toBuilder()
+                .replaceHeader(HttpHeaders.AUTHORIZATION,
+                    AbiquoAuthentication.basicAuth("identity", "credential")).build();
+
+        assertFalse(filtered.getHeaders().containsKey(HttpHeaders.COOKIE));
+        assertEquals(filtered, expected);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testBasicAuthenticationWithoutIdentity() throws UnsupportedEncodingException,
+        NoSuchAlgorithmException, CertificateException
+    {
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).build();
+
+        AbiquoAuthentication filter = new AbiquoAuthentication(null, "credential", "false");
+        filter.filter(request);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testBasicAuthenticationWithoutCredential() throws UnsupportedEncodingException,
+        NoSuchAlgorithmException, CertificateException
+    {
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).build();
+
+        AbiquoAuthentication filter = new AbiquoAuthentication("identity", null, "false");
+        filter.filter(request);
+    }
+
+    public void testTokenAuthentication() throws UnsupportedEncodingException,
+        NoSuchAlgorithmException, CertificateException
+    {
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).build();
+
+        AbiquoAuthentication filter = new AbiquoAuthentication("token-identity", "token", "true");
+        HttpRequest filtered = filter.filter(request);
+        HttpRequest expected =
+            request.toBuilder()
+                .replaceHeader(HttpHeaders.COOKIE, AbiquoAuthentication.tokenAuth("token")).build();
+
+        assertFalse(filtered.getHeaders().containsKey(HttpHeaders.AUTHORIZATION));
+        assertEquals(filtered, expected);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AppendApiVersionToMediaTypeTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AppendApiVersionToMediaTypeTest.java
new file mode 100644
index 0000000..02ce282
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/http/filters/AppendApiVersionToMediaTypeTest.java
@@ -0,0 +1,310 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.http.filters;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.Collection;
+
+import javax.ws.rs.core.HttpHeaders;
+
+import org.jclouds.abiquo.AbiquoAsyncApi;
+import org.jclouds.abiquo.functions.AppendApiVersionToAbiquoMimeType;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+
+/**
+ * Unit tests for the {@link AppendApiVersionToMediaType} filter.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AppendApiVersionToMediaTypeTest")
+public class AppendApiVersionToMediaTypeTest
+{
+
+    public void testAppendVersionToNonPayloadHeadersWithoutHeaders()
+    {
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToNonPayloadHeaders(request);
+
+        assertTrue(filtered.getHeaders().get(HttpHeaders.ACCEPT).isEmpty());
+    }
+
+    public void testAppendVersionToNonPayloadHeadersWithStandardMediaType()
+    {
+        Multimap<String, String> headers = LinkedHashMultimap.<String, String> create();
+        headers.put(HttpHeaders.ACCEPT, "application/xml");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).headers(headers)
+                .build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToNonPayloadHeaders(request);
+
+        Collection<String> contentType = filtered.getHeaders().get(HttpHeaders.ACCEPT);
+        assertEquals(contentType.size(), 1);
+        assertEquals(contentType.iterator().next(), "application/xml");
+    }
+
+    public void testAppendVersionToNonPayloadHeadersWithVersionInMediaType()
+    {
+        Multimap<String, String> headers = LinkedHashMultimap.<String, String> create();
+        headers.put(HttpHeaders.ACCEPT, "application/vnd.abiquo.racks+xml;version=2.1-SNAPSHOT");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).headers(headers)
+                .build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToNonPayloadHeaders(request);
+
+        Collection<String> contentType = filtered.getHeaders().get(HttpHeaders.ACCEPT);
+        assertEquals(contentType.size(), 1);
+        assertEquals(contentType.iterator().next(),
+            "application/vnd.abiquo.racks+xml;version=2.1-SNAPSHOT");
+    }
+
+    public void testAppendVersionToNonPayloadHeadersWithoutVersionInMediaType()
+    {
+        Multimap<String, String> headers = LinkedHashMultimap.<String, String> create();
+        headers.put(HttpHeaders.ACCEPT, "application/vnd.abiquo.racks+xml");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).headers(headers)
+                .build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToNonPayloadHeaders(request);
+
+        Collection<String> accept = filtered.getHeaders().get(HttpHeaders.ACCEPT);
+        assertEquals(accept.size(), 1);
+        assertEquals(accept.iterator().next(), "application/vnd.abiquo.racks+xml;version="
+            + AbiquoAsyncApi.API_VERSION);
+    }
+
+    public void testAppendVersionToPayloadHeadersWithoutPayload()
+    {
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToPayloadHeaders(request);
+
+        assertNull(filtered.getPayload());
+    }
+
+    public void testAppendVersionToPayloadHeadersWithStandardPayload()
+    {
+        Payload payload = Payloads.newByteArrayPayload(new byte[] {});
+        payload.getContentMetadata().setContentType("application/xml");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).payload(payload)
+                .build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToPayloadHeaders(request);
+
+        assertEquals(filtered.getPayload().getContentMetadata().getContentType(), "application/xml");
+    }
+
+    public void testAppendVersionToPayloadHeadersWithDefaultPayload()
+    {
+        Payload payload = Payloads.newByteArrayPayload(new byte[] {});
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).payload(payload)
+                .build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToPayloadHeaders(request);
+
+        assertEquals(filtered.getPayload().getContentMetadata().getContentType(),
+            "application/unknown");
+    }
+
+    public void testAppendVersionToPayloadHeadersWithVersionInPayload()
+    {
+        Payload payload = Payloads.newByteArrayPayload(new byte[] {});
+        payload.getContentMetadata().setContentType(
+            "application/vnd.abiquo.racks+xml;version=1.8.5");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).payload(payload)
+                .build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToPayloadHeaders(request);
+
+        assertEquals(filtered.getPayload().getContentMetadata().getContentType(),
+            "application/vnd.abiquo.racks+xml;version=1.8.5");
+    }
+
+    public void testAppendVersionToPayloadHeadersWithoutVersionInPayload()
+    {
+        Payload payload = Payloads.newByteArrayPayload(new byte[] {});
+        payload.getContentMetadata().setContentType("application/vnd.abiquo.racks+xml");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).payload(payload)
+                .build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.appendVersionToPayloadHeaders(request);
+
+        assertEquals(filtered.getPayload().getContentMetadata().getContentType(),
+            "application/vnd.abiquo.racks+xml;version=" + AbiquoAsyncApi.API_VERSION);
+    }
+
+    public void testFilterWithAcceptAndContentTypeWithVersion()
+    {
+        Payload payload = Payloads.newByteArrayPayload(new byte[] {});
+        payload.getContentMetadata().setContentType(
+            "application/vnd.abiquo.racks+xml;version=2.1-SNAPSHOT");
+
+        Multimap<String, String> headers = LinkedHashMultimap.<String, String> create();
+        headers.put(HttpHeaders.ACCEPT, "application/vnd.abiquo.racks+xml;version=2.1-SNAPSHOT");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).headers(headers)
+                .payload(payload).build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.filter(request);
+
+        Collection<String> accept = filtered.getHeaders().get(HttpHeaders.ACCEPT);
+        assertEquals(accept.size(), 1);
+        assertEquals(accept.iterator().next(),
+            "application/vnd.abiquo.racks+xml;version=2.1-SNAPSHOT");
+
+        assertEquals(filtered.getPayload().getContentMetadata().getContentType(),
+            "application/vnd.abiquo.racks+xml;version=2.1-SNAPSHOT");
+    }
+
+    public void testFilterWithAcceptAndContentTypeWithoutVersion()
+    {
+        Payload payload = Payloads.newByteArrayPayload(new byte[] {});
+        payload.getContentMetadata().setContentType("application/vnd.abiquo.racks+xml");
+
+        Multimap<String, String> headers = LinkedHashMultimap.<String, String> create();
+        headers.put(HttpHeaders.ACCEPT, "application/vnd.abiquo.racks+xml");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).headers(headers)
+                .payload(payload).build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.filter(request);
+
+        Collection<String> accept = filtered.getHeaders().get(HttpHeaders.ACCEPT);
+        assertEquals(accept.size(), 1);
+        assertEquals(accept.iterator().next(), "application/vnd.abiquo.racks+xml;version="
+            + AbiquoAsyncApi.API_VERSION);
+
+        assertEquals(filtered.getPayload().getContentMetadata().getContentType(),
+            "application/vnd.abiquo.racks+xml;version=" + AbiquoAsyncApi.API_VERSION);
+    }
+
+    public void testFilterWithversionInAccept()
+    {
+        Payload payload = Payloads.newByteArrayPayload(new byte[] {});
+        payload.getContentMetadata().setContentType("application/vnd.abiquo.racks+xml");
+
+        Multimap<String, String> headers = LinkedHashMultimap.<String, String> create();
+        headers.put(HttpHeaders.ACCEPT, "application/vnd.abiquo.racks+xml;version=1.8.5");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).headers(headers)
+                .payload(payload).build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.filter(request);
+
+        Collection<String> accept = filtered.getHeaders().get(HttpHeaders.ACCEPT);
+        assertEquals(accept.size(), 1);
+        assertEquals(accept.iterator().next(), "application/vnd.abiquo.racks+xml;version=1.8.5");
+
+        assertEquals(filtered.getPayload().getContentMetadata().getContentType(),
+            "application/vnd.abiquo.racks+xml;version=" + AbiquoAsyncApi.API_VERSION);
+    }
+
+    public void testFilterWithversionInContentType()
+    {
+        Payload payload = Payloads.newByteArrayPayload(new byte[] {});
+        payload.getContentMetadata().setContentType(
+            "application/vnd.abiquo.racks+xml;version=1.8.5");
+
+        Multimap<String, String> headers = LinkedHashMultimap.<String, String> create();
+        headers.put(HttpHeaders.ACCEPT, "application/vnd.abiquo.racks+xml");
+
+        HttpRequest request =
+            HttpRequest.builder().method("GET").endpoint(URI.create("http://foo")).headers(headers)
+                .payload(payload).build();
+
+        AppendApiVersionToMediaType filter =
+            new AppendApiVersionToMediaType(new AppendApiVersionToAbiquoMimeType(AbiquoAsyncApi.API_VERSION));
+
+        HttpRequest filtered = filter.filter(request);
+
+        Collection<String> accept = filtered.getHeaders().get(HttpHeaders.ACCEPT);
+        assertEquals(accept.size(), 1);
+        assertEquals(accept.iterator().next(), "application/vnd.abiquo.racks+xml;version="
+            + AbiquoAsyncApi.API_VERSION);
+
+        assertEquals(filtered.getPayload().getContentMetadata().getContentType(),
+            "application/vnd.abiquo.racks+xml;version=1.8.5");
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/AsyncMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/AsyncMonitorTest.java
new file mode 100644
index 0000000..0a45f0a
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/AsyncMonitorTest.java
@@ -0,0 +1,523 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.events.monitor.MonitorEvent;
+import org.jclouds.abiquo.internal.BaseMonitoringService.AsyncMonitor;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * Unit tests for the {@link AsyncMonitor} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AsyncMonitorTest")
+public class AsyncMonitorTest
+{
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testStartMonitoringWithoutTimeout()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE),
+                new EventBus());
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(null);
+
+        assertNotNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testStartMonitoringWithTimeout()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE),
+                new EventBus());
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(100L);
+
+        assertNotNull(monitor.getFuture());
+        assertNotNull(monitor.getTimeout());
+        assertTrue(monitor.getTimeout() > 100L);
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testIsTimeoutWhenNullTimeout()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE),
+                new EventBus());
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(null);
+        assertNotNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+        assertFalse(monitor.isTimeout());
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testIsTimeoutReturnsFalseWhenNotFinished()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE),
+                new EventBus());
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(60000L);
+        assertNotNull(monitor.getFuture());
+        assertNotNull(monitor.getTimeout());
+        assertFalse(monitor.isTimeout());
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testIsTimeoutReturnsTrueWhenFinished() throws InterruptedException
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE),
+                new EventBus());
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(1L);
+        Thread.sleep(2L);
+        assertNotNull(monitor.getFuture());
+        assertNotNull(monitor.getTimeout());
+        assertTrue(monitor.isTimeout());
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testStopMonitoringWhenFutureIsCancelled()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        expect(mockFuture.isCancelled()).andReturn(true);
+
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE),
+                new EventBus());
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(null);
+        assertNotNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.stopMonitoring();
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testStopMonitoringWhenFutureIsDone()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        expect(mockFuture.isCancelled()).andReturn(false);
+        expect(mockFuture.isDone()).andReturn(true);
+
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE),
+                new EventBus());
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(null);
+        assertNotNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.stopMonitoring();
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testStopMonitoringWhenFutureIsNotComplete()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        expect(mockFuture.isCancelled()).andReturn(false);
+        expect(mockFuture.isDone()).andReturn(false);
+        expect(mockFuture.cancel(false)).andReturn(true);
+
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE),
+                new EventBus());
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(null);
+        assertNotNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.stopMonitoring();
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testMonitorAndDone()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        expect(mockFuture.isCancelled()).andReturn(true);
+
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        CoutingEventHandler handler = new CoutingEventHandler();
+        EventBus eventBus = new EventBus();
+        eventBus.register(handler);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.DONE), eventBus);
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(null);
+        assertNotNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.run();
+        assertEquals(handler.numCompletes, 1);
+        assertEquals(handler.numFailures, 0);
+        assertEquals(handler.numTimeouts, 0);
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testMonitorAndFail()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        expect(mockFuture.isCancelled()).andReturn(true);
+
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        CoutingEventHandler handler = new CoutingEventHandler();
+        EventBus eventBus = new EventBus();
+        eventBus.register(handler);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.FAILED), eventBus);
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(null);
+        assertNotNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.run();
+        assertEquals(handler.numCompletes, 0);
+        assertEquals(handler.numFailures, 1);
+        assertEquals(handler.numTimeouts, 0);
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testMonitorAndContinueWithoutTimeout()
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        CoutingEventHandler handler = new CoutingEventHandler();
+        EventBus eventBus = new EventBus();
+        eventBus.register(handler);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.CONTINUE), eventBus);
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(null);
+        assertNotNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.run();
+        assertEquals(handler.numCompletes, 0);
+        assertEquals(handler.numFailures, 0);
+        assertEquals(handler.numTimeouts, 0);
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testMonitorAndContinueWithtTimeout() throws InterruptedException
+    {
+        ScheduledFuture mockFuture = EasyMock.createMock(ScheduledFuture.class);
+        expect(mockFuture.isCancelled()).andReturn(true);
+
+        ScheduledExecutorService schedulerMock =
+            EasyMock.createMock(ScheduledExecutorService.class);
+        expect(
+            schedulerMock.scheduleWithFixedDelay(anyObject(Runnable.class), anyLong(), anyLong(),
+                anyObject(TimeUnit.class))).andReturn(mockFuture);
+
+        replay(mockFuture);
+        replay(schedulerMock);
+
+        CoutingEventHandler handler = new CoutingEventHandler();
+        EventBus eventBus = new EventBus();
+        eventBus.register(handler);
+
+        AsyncMonitor<Object> monitor =
+            mockMonitor(schedulerMock, new Object(), mockFunction(MonitorStatus.CONTINUE), eventBus);
+
+        assertNull(monitor.getFuture());
+        assertNull(monitor.getTimeout());
+
+        monitor.startMonitoring(1L);
+        assertNotNull(monitor.getFuture());
+        assertNotNull(monitor.getTimeout());
+
+        Thread.sleep(2L);
+        monitor.run();
+        assertEquals(handler.numCompletes, 0);
+        assertEquals(handler.numFailures, 0);
+        assertEquals(handler.numTimeouts, 1);
+
+        verify(mockFuture);
+        verify(schedulerMock);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testCreateMonitorWithNullObject()
+    {
+        mockMonitor(null, null, new Function<Object, MonitorStatus>()
+        {
+            @Override
+            public MonitorStatus apply(final Object input)
+            {
+                return MonitorStatus.DONE;
+            }
+        }, new EventBus());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testCreateMonitorWithNullFunction()
+    {
+        mockMonitor(null, new Object(), null, new EventBus());
+    }
+
+    @SuppressWarnings("unchecked")
+    private AsyncMonitor<Object> mockMonitor(final ScheduledExecutorService scheduler,
+        final Object object, final Function<Object, MonitorStatus> function, final EventBus eventBus)
+    {
+        BaseMonitoringService monitorService =
+            new BaseMonitoringService(EasyMock.createMock(RestContext.class),
+                scheduler,
+                100L,
+                eventBus);
+
+        return monitorService.new AsyncMonitor<Object>(object, function);
+    }
+
+    private Function<Object, MonitorStatus> mockFunction(final MonitorStatus status)
+    {
+        return new Function<Object, MonitorStatus>()
+        {
+            @Override
+            public MonitorStatus apply(final Object input)
+            {
+                return status;
+            }
+        };
+    }
+
+    private static class CoutingEventHandler
+    {
+        public int numCompletes = 0;
+
+        public int numFailures = 0;
+
+        public int numTimeouts = 0;
+
+        @Subscribe
+        @SuppressWarnings("unused")
+        public void handle(final MonitorEvent< ? > event)
+        {
+            switch (event.getType())
+            {
+                case COMPLETED:
+                    numCompletes++;
+                    break;
+                case FAILED:
+                    numFailures++;
+                    break;
+                case TIMEOUT:
+                    numTimeouts++;
+                    break;
+            }
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAbiquoApiLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAbiquoApiLiveApiTest.java
new file mode 100644
index 0000000..40fc5fa
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAbiquoApiLiveApiTest.java
@@ -0,0 +1,105 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import org.jclouds.abiquo.environment.CloudTestEnvironment;
+import org.testng.annotations.AfterSuite;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+
+/**
+ * Base class for live and domain tests.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "BaseAbiquoApiLiveApiTest", singleThreaded = true)
+public abstract class BaseAbiquoApiLiveApiTest extends BaseAbiquoLiveApiTest
+{
+    /** The test environment. */
+    protected static CloudTestEnvironment env;
+
+    @Override
+    @BeforeSuite(groups = "api")
+    public void setupContext()
+    {
+        super.setupContext();
+        setupEnvironment();
+    }
+
+    // @BeforeSuite(groups = "ucs", dependsOnMethods = "setupContext")
+    protected void setupUcsEnvironment() throws Exception
+    {
+        if (env != null)
+        {
+            env.createUcsRack();
+        }
+    }
+
+    @Override
+    @AfterSuite(groups = "api")
+    protected void tearDownContext()
+    {
+        try
+        {
+            tearDownEnvironment();
+        }
+        finally
+        {
+            // Make sure we close the context
+            super.tearDownContext();
+        }
+    }
+
+    protected void setupEnvironment()
+    {
+        if (env == null)
+        {
+            try
+            {
+                env = new CloudTestEnvironment(view);
+                env.setup();
+            }
+            catch (Exception ex)
+            {
+                super.tearDownContext(); // Make sure we close the context setup fails
+                throw new RuntimeException("Could not create environment", ex);
+            }
+        }
+    }
+
+    protected void tearDownEnvironment()
+    {
+        if (env != null)
+        {
+            try
+            {
+                env.tearDown();
+
+                // Wait a bit before closing context, to avoid executor shutdown while
+                // there are still open threads
+                Thread.sleep(1000L);
+            }
+            catch (Exception ex)
+            {
+                throw new RuntimeException("Could not tear down environment", ex);
+            }
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAbiquoLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAbiquoLiveApiTest.java
new file mode 100644
index 0000000..290c449
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAbiquoLiveApiTest.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import java.util.Properties;
+
+import org.jclouds.Constants;
+import org.jclouds.abiquo.AbiquoContext;
+import org.jclouds.apis.BaseViewLiveTest;
+import org.jclouds.logging.config.LoggingModule;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * Base class for Abiquo live tests.
+ * 
+ * @author Ignasi Barrera
+ */
+public abstract class BaseAbiquoLiveApiTest extends BaseViewLiveTest<AbiquoContext>
+{
+    public BaseAbiquoLiveApiTest()
+    {
+        provider = "abiquo";
+    }
+
+    @Override
+    protected Properties setupProperties()
+    {
+        Properties overrides = super.setupProperties();
+        overrides.put(Constants.PROPERTY_MAX_RETRIES, "0");
+        overrides.put(Constants.PROPERTY_MAX_REDIRECTS, "0");
+        // Wait at most one minute in Machine discovery
+        overrides.put("jclouds.timeouts.InfrastructureApi.discoverSingleMachine", "60000");
+        overrides.put("jclouds.timeouts.InfrastructureApi.discoverMultipleMachines", "60000");
+        overrides.put("jclouds.timeouts.InfrastructureApi.createMachine", "60000");
+        overrides.put("jclouds.timeouts.InfrastructureApi.updateMachine", "60000");
+        overrides.put("jclouds.timeouts.InfrastructureApi.checkMachineState", "60000");
+        overrides.put("jclouds.timeouts.CloudApi.listVirtualMachines", "60000");
+        return overrides;
+    }
+
+    @Override
+    protected LoggingModule getLoggingModule()
+    {
+        return new SLF4JLoggingModule();
+    }
+
+    @Override
+    protected TypeToken<AbiquoContext> viewType()
+    {
+        return TypeToken.of(AbiquoContext.class);
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAdministrationServiceTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAdministrationServiceTest.java
new file mode 100644
index 0000000..f95f5de
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseAdministrationServiceTest.java
@@ -0,0 +1,51 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.features.services.AdministrationService;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BaseAdministrationService} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BaseAdministrationServiceTest")
+public class BaseAdministrationServiceTest extends BaseInjectionTest
+{
+
+    public void testAllPropertiesInjected()
+    {
+        BaseAdministrationService service =
+            (BaseAdministrationService) injector.getInstance(AdministrationService.class);
+
+        assertNotNull(service.context);
+        assertNotNull(service.listDatacenters);
+        assertNotNull(service.listMachines);
+        assertNotNull(service.listEnterprises);
+        assertNotNull(service.listLicenses);
+        assertNotNull(service.listPrivileges);
+        assertNotNull(service.listRoles);
+        assertNotNull(service.currentUser);
+        assertNotNull(service.currentEnterprise);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseCloudServiceTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseCloudServiceTest.java
new file mode 100644
index 0000000..e90806b
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseCloudServiceTest.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.features.services.CloudService;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BaseCloudService} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BaseCloudServiceTest")
+public class BaseCloudServiceTest extends BaseInjectionTest
+{
+
+    public void testAllPropertiesInjected()
+    {
+        BaseCloudService service = (BaseCloudService) injector.getInstance(CloudService.class);
+
+        assertNotNull(service.context);
+        assertNotNull(service.listVirtualDatacenters);
+        assertNotNull(service.listVirtualAppliances);
+        assertNotNull(service.listVirtualMachines);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseEventServiceTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseEventServiceTest.java
new file mode 100644
index 0000000..39a6fd3
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseEventServiceTest.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.features.services.EventService;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BaseEventService} class.
+ * 
+ * @author Vivien Mahé
+ */
+@Test(groups = "unit", testName = "BaseEventServiceTest")
+public class BaseEventServiceTest extends BaseInjectionTest
+{
+    public void testAllPropertiesInjected()
+    {
+        BaseEventService service = (BaseEventService) injector.getInstance(EventService.class);
+
+        assertNotNull(service.context);
+        assertNotNull(service.listEvents);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseInjectionTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseInjectionTest.java
new file mode 100644
index 0000000..3749a80
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseInjectionTest.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import java.util.Properties;
+
+import org.jclouds.ContextBuilder;
+import org.jclouds.abiquo.AbiquoApiMetadata;
+import org.jclouds.abiquo.AbiquoContext;
+import org.jclouds.lifecycle.Closer;
+import org.jclouds.logging.config.NullLoggingModule;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+
+/**
+ * Unit tests for the {@link BaseCloudService} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BaseEventServiceTest")
+public class BaseInjectionTest
+{
+    protected Injector injector;
+
+    @BeforeClass
+    public void setup()
+    {
+        injector = ContextBuilder.newBuilder(new AbiquoApiMetadata()) //
+            .credentials("identity", "credential") //
+            .modules(ImmutableSet.<Module> of(new NullLoggingModule())) //
+            .overrides(buildProperties()) //
+            .build(AbiquoContext.class).getUtils().getInjector();
+    }
+
+    protected Properties buildProperties()
+    {
+        return new Properties();
+    }
+
+    @AfterClass
+    public void tearDown() throws Exception
+    {
+        if (injector != null)
+        {
+            injector.getInstance(Closer.class).close();
+        }
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseMonitoringServiceTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseMonitoringServiceTest.java
new file mode 100644
index 0000000..6d58677
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseMonitoringServiceTest.java
@@ -0,0 +1,260 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static org.jclouds.abiquo.config.AbiquoProperties.ASYNC_TASK_MONITOR_DELAY;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.abiquo.events.handlers.BlockingEventHandler;
+import org.jclouds.abiquo.events.monitor.MonitorEvent;
+import org.jclouds.abiquo.features.services.MonitoringService;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link BaseMonitoringService} class.
+ * 
+ * @author Ignasi Barrera
+ */
+// Since these tests block the thread, mark them as failed after the given timeout
+@Test(groups = "unit", testName = "BaseMonitoringServiceTest", timeOut = 10000L)
+public class BaseMonitoringServiceTest extends BaseInjectionTest
+{
+    // The polling interval used in tests (in ms)
+    private static final long TEST_MONITOR_POLLING = 100L;
+
+    @Override
+    protected Properties buildProperties()
+    {
+        // Use a small monitor polling interval in tests (in ms)
+        Properties props = super.buildProperties();
+        props.setProperty(ASYNC_TASK_MONITOR_DELAY, String.valueOf(TEST_MONITOR_POLLING));
+        return props;
+    }
+
+    public void testAllPropertiesInjected()
+    {
+        BaseMonitoringService service =
+            (BaseMonitoringService) injector.getInstance(MonitoringService.class);
+
+        assertNotNull(service.context);
+        assertNotNull(service.scheduler);
+        assertNotNull(service.pollingDelay);
+        assertNotNull(service.eventBus);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testAwaitCompletionWithNullFunction()
+    {
+        monitoringService().awaitCompletion(null, new Object[] {});
+    }
+
+    public void testAwaitCompletionWithoutTasks()
+    {
+        BaseMonitoringService service = monitoringService();
+
+        service.awaitCompletion(new MockMonitor());
+        service.awaitCompletion(new MockMonitor(), (Object[]) null);
+        service.awaitCompletion(new MockMonitor(), new Object[] {});
+    }
+
+    public void testAwaitCompletion()
+    {
+        BaseMonitoringService service = monitoringService();
+        service.awaitCompletion(new MockMonitor(), new Object());
+    }
+
+    public void testAwaitCompletionMultipleTasks()
+    {
+        BaseMonitoringService service = monitoringService();
+        service.awaitCompletion(new MockMonitor(), new Object(), new Object());
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testMonitorWithNullCompletecondition()
+    {
+        monitoringService().monitor(null, (Object[]) null);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testBlockingHandlerWithoutArguments()
+    {
+        new BlockingEventHandler<Object>();
+    }
+
+    public void testMonitor()
+    {
+        BaseMonitoringService service = monitoringService();
+
+        Object monitoredObject = new Object();
+        CountingHandler handler = new CountingHandler(monitoredObject);
+        service.register(handler);
+
+        service.monitor(new MockMonitor(), monitoredObject);
+        handler.lock();
+
+        service.unregister(handler);
+
+        assertEquals(handler.numCompletes, 1);
+        assertEquals(handler.numFailures, 0);
+        assertEquals(handler.numTimeouts, 0);
+    }
+
+    public void testMonitorMultipleTasks()
+    {
+        BaseMonitoringService service = monitoringService();
+
+        Object monitoredObject1 = new Object();
+        Object monitoredObject2 = new Object();
+        CountingHandler handler = new CountingHandler(monitoredObject1, monitoredObject2);
+        service.register(handler);
+
+        service.monitor(new MockMonitor(), monitoredObject1, monitoredObject2);
+        handler.lock();
+
+        service.unregister(handler);
+
+        assertEquals(handler.numCompletes, 2);
+        assertEquals(handler.numFailures, 0);
+        assertEquals(handler.numTimeouts, 0);
+    }
+
+    public void testMonitorReachesTimeout()
+    {
+        BaseMonitoringService service = monitoringService();
+
+        Object monitoredObject = new Object();
+        CountingHandler handler = new CountingHandler(monitoredObject);
+        service.register(handler);
+
+        service.monitor(TEST_MONITOR_POLLING + 10L, TimeUnit.MILLISECONDS,
+            new MockInfiniteMonitor(), monitoredObject);
+        handler.lock();
+
+        service.unregister(handler);
+
+        assertEquals(handler.numCompletes, 0);
+        assertEquals(handler.numFailures, 0);
+        assertEquals(handler.numTimeouts, 1);
+    }
+
+    public void testMonitorMultipleTasksReachesTimeout()
+    {
+        BaseMonitoringService service = monitoringService();
+
+        Object monitoredObject1 = new Object();
+        Object monitoredObject2 = new Object();
+        CountingHandler handler = new CountingHandler(monitoredObject1, monitoredObject2);
+        service.register(handler);
+
+        service.monitor(TEST_MONITOR_POLLING + 10L, TimeUnit.MILLISECONDS,
+            new MockInfiniteMonitor(), monitoredObject1, monitoredObject2);
+        handler.lock();
+
+        service.unregister(handler);
+
+        assertEquals(handler.numCompletes, 0);
+        assertEquals(handler.numFailures, 0);
+        assertEquals(handler.numTimeouts, 2);
+    }
+
+    public void testDelegateToVirtualMachineMonitor()
+    {
+        assertNotNull(monitoringService().getVirtualMachineMonitor());
+    }
+
+    public void testDelegateToVirtualApplianceMonitor()
+    {
+        assertNotNull(monitoringService().getVirtualApplianceMonitor());
+    }
+
+    public void testDelegateToAsyncTaskMonitor()
+    {
+        assertNotNull(monitoringService().getAsyncTaskMonitor());
+    }
+
+    private BaseMonitoringService monitoringService()
+    {
+        return injector.getInstance(BaseMonitoringService.class);
+    }
+
+    private static class MockMonitor implements Function<Object, MonitorStatus>
+    {
+        private int finishAfterCount;
+
+        public MockMonitor()
+        {
+            this.finishAfterCount = 1; // Simulate task completion after one refresh
+        }
+
+        @Override
+        public MonitorStatus apply(final Object object)
+        {
+            return finishAfterCount-- <= 0 ? MonitorStatus.DONE : MonitorStatus.CONTINUE;
+        }
+    }
+
+    private static class MockInfiniteMonitor implements Function<Object, MonitorStatus>
+    {
+        @Override
+        public MonitorStatus apply(final Object object)
+        {
+            return MonitorStatus.CONTINUE;
+        }
+    }
+
+    private static class CountingHandler extends BlockingEventHandler<Object>
+    {
+        public int numCompletes = 0;
+
+        public int numFailures = 0;
+
+        public int numTimeouts = 0;
+
+        public CountingHandler(final Object... lockedObjects)
+        {
+            super(lockedObjects);
+        }
+
+        @Override
+        protected void doBeforeRelease(final MonitorEvent<Object> event)
+        {
+            switch (event.getType())
+            {
+                case COMPLETED:
+                    numCompletes++;
+                    break;
+                case FAILED:
+                    numFailures++;
+                    break;
+                case TIMEOUT:
+                    numTimeouts++;
+                    break;
+            }
+        }
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseSearchServiceTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseSearchServiceTest.java
new file mode 100644
index 0000000..1bd84c6
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/internal/BaseSearchServiceTest.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.internal;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.features.services.SearchService;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BaseSearchService} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BaseSearchServiceTest")
+public class BaseSearchServiceTest extends BaseInjectionTest
+{
+
+    public void testAllPropertiesInjected()
+    {
+        BaseSearchService service = (BaseSearchService) injector.getInstance(SearchService.class);
+
+        assertNotNull(service.context);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitorTest.java
new file mode 100644
index 0000000..4c7b626
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitorTest.java
@@ -0,0 +1,118 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.task.TaskDto;
+import com.abiquo.server.core.task.enums.TaskState;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link AsyncTaskStatusMonitor} function.
+ * 
+ * @author Serafin Sedano
+ */
+@Test(groups = "unit", testName = "AsyncTaskStatusMonitorTest")
+public class AsyncTaskStatusMonitorTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullArgument()
+    {
+        Function<AsyncTask, MonitorStatus> function = new AsyncTaskStatusMonitor();
+        function.apply(null);
+    }
+
+    public void testReturnDone()
+    {
+        TaskState[] states = {TaskState.FINISHED_SUCCESSFULLY};
+
+        checkStatesReturn(new MockAsyncTask(), new AsyncTaskStatusMonitor(), states,
+            MonitorStatus.DONE);
+    }
+
+    public void testReturnFail()
+    {
+        TaskState[] states = {TaskState.ABORTED, TaskState.FINISHED_UNSUCCESSFULLY};
+
+        checkStatesReturn(new MockAsyncTask(), new AsyncTaskStatusMonitor(), states,
+            MonitorStatus.FAILED);
+    }
+
+    public void testReturnContinue()
+    {
+        TaskState[] states = {TaskState.STARTED, TaskState.PENDING};
+
+        checkStatesReturn(new MockAsyncTask(), new AsyncTaskStatusMonitor(), states,
+            MonitorStatus.CONTINUE);
+
+        checkStatesReturn(new MockAsyncTaskFailing(), new AsyncTaskStatusMonitor(), states,
+            MonitorStatus.CONTINUE);
+    }
+
+    private void checkStatesReturn(final MockAsyncTask task,
+        final Function<AsyncTask, MonitorStatus> function, final TaskState[] states,
+        final MonitorStatus expectedStatus)
+    {
+        for (TaskState state : states)
+        {
+            task.setState(state);
+            assertEquals(function.apply(task), expectedStatus);
+        }
+    }
+
+    private static class MockAsyncTask extends AsyncTask
+    {
+        @SuppressWarnings("unchecked")
+        public MockAsyncTask()
+        {
+            super(EasyMock.createMock(RestContext.class), new TaskDto());
+        }
+
+        @Override
+        public void refresh()
+        {
+            // Do not perform any API call
+        }
+
+        public void setState(final TaskState state)
+        {
+            target.setState(state);
+        }
+    }
+
+    private static class MockAsyncTaskFailing extends MockAsyncTask
+    {
+        @Override
+        public void refresh()
+        {
+            throw new RuntimeException("This mock class always fails to refresh");
+        }
+
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/ConversionStatusMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/ConversionStatusMonitorTest.java
new file mode 100644
index 0000000..912e155
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/ConversionStatusMonitorTest.java
@@ -0,0 +1,118 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.domain.cloud.Conversion;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.enumerator.ConversionState;
+import com.abiquo.server.core.appslibrary.ConversionDto;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link ConversionStatusMonitor} function.
+ * 
+ * @author Sergi Castro
+ */
+@Test(groups = "unit", testName = "ConversionStatusMonitorTest")
+public class ConversionStatusMonitorTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullArgument()
+    {
+        Function<Conversion, MonitorStatus> function = new ConversionStatusMonitor();
+        function.apply(null);
+    }
+
+    public void testReturnDone()
+    {
+        ConversionState[] states = {ConversionState.FINISHED};
+
+        checkStatesReturn(new MockConversion(), new ConversionStatusMonitor(), states,
+            MonitorStatus.DONE);
+    }
+
+    public void testReturnFail()
+    {
+        ConversionState[] states = {ConversionState.FAILED};
+
+        checkStatesReturn(new MockConversion(), new ConversionStatusMonitor(), states,
+            MonitorStatus.FAILED);
+    }
+
+    public void testReturnContinue()
+    {
+        ConversionState[] states = {ConversionState.ENQUEUED};
+
+        checkStatesReturn(new MockConversion(), new ConversionStatusMonitor(), states,
+            MonitorStatus.CONTINUE);
+
+        checkStatesReturn(new MockConversionFailing(), new ConversionStatusMonitor(), states,
+            MonitorStatus.CONTINUE);
+    }
+
+    private void checkStatesReturn(final MockConversion task,
+        final Function<Conversion, MonitorStatus> function, final ConversionState[] states,
+        final MonitorStatus expectedStatus)
+    {
+        for (ConversionState state : states)
+        {
+            task.setState(state);
+            assertEquals(function.apply(task), expectedStatus);
+        }
+    }
+
+    private static class MockConversion extends Conversion
+    {
+        @SuppressWarnings("unchecked")
+        public MockConversion()
+        {
+            super(EasyMock.createMock(RestContext.class), new ConversionDto());
+        }
+
+        @Override
+        public void refresh()
+        {
+            // Do not perform any API call
+        }
+
+        public void setState(final ConversionState state)
+        {
+            target.setState(state);
+        }
+    }
+
+    private static class MockConversionFailing extends MockConversion
+    {
+        @Override
+        public void refresh()
+        {
+            throw new RuntimeException("This mock class always fails to refresh");
+        }
+
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceDeployMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceDeployMonitorTest.java
new file mode 100644
index 0000000..2615978
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceDeployMonitorTest.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualApplianceState;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link VirtualApplianceDeployMonitor} function.
+ * 
+ * @author Serafin Sedano
+ */
+@Test(groups = "unit", testName = "VirtualApplianceDeployMonitorTest")
+public class VirtualApplianceDeployMonitorTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullArgument()
+    {
+        Function<VirtualAppliance, MonitorStatus> function = new VirtualApplianceDeployMonitor();
+        function.apply(null);
+    }
+
+    public void testReturnDone()
+    {
+        VirtualApplianceState[] states = {VirtualApplianceState.DEPLOYED};
+
+        checkStatesReturn(new MockVirtualAppliance(), new VirtualApplianceDeployMonitor(), states,
+            MonitorStatus.DONE);
+    }
+
+    public void testReturnFail()
+    {
+        VirtualApplianceState[] states =
+            {VirtualApplianceState.NEEDS_SYNC, VirtualApplianceState.UNKNOWN,
+            VirtualApplianceState.NOT_DEPLOYED};
+
+        checkStatesReturn(new MockVirtualAppliance(), new VirtualApplianceDeployMonitor(), states,
+            MonitorStatus.FAILED);
+    }
+
+    public void testReturnContinue()
+    {
+        VirtualApplianceState[] states = {VirtualApplianceState.LOCKED};
+
+        checkStatesReturn(new MockVirtualAppliance(), new VirtualApplianceDeployMonitor(), states,
+            MonitorStatus.CONTINUE);
+
+        checkStatesReturn(new MockVirtualApplianceFailing(), new VirtualApplianceDeployMonitor(),
+            states, MonitorStatus.CONTINUE);
+    }
+
+    private void checkStatesReturn(final MockVirtualAppliance vapp,
+        final Function<VirtualAppliance, MonitorStatus> function,
+        final VirtualApplianceState[] states, final MonitorStatus expectedStatus)
+    {
+        for (VirtualApplianceState state : states)
+        {
+            vapp.setState(state);
+            assertEquals(function.apply(vapp), expectedStatus);
+        }
+    }
+
+    private static class MockVirtualAppliance extends VirtualAppliance
+    {
+        private VirtualApplianceState state;
+
+        @SuppressWarnings("unchecked")
+        public MockVirtualAppliance()
+        {
+            super(EasyMock.createMock(RestContext.class), new VirtualApplianceDto());
+        }
+
+        @Override
+        public VirtualApplianceState getState()
+        {
+            return state;
+        }
+
+        public void setState(final VirtualApplianceState state)
+        {
+            this.state = state;
+        }
+    }
+
+    private static class MockVirtualApplianceFailing extends MockVirtualAppliance
+    {
+        @Override
+        public VirtualApplianceState getState()
+        {
+            throw new RuntimeException("This mock class always fails to get the state");
+        }
+
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceUndeployMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceUndeployMonitorTest.java
new file mode 100644
index 0000000..103b76b
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualApplianceUndeployMonitorTest.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualApplianceDto;
+import com.abiquo.server.core.cloud.VirtualApplianceState;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link VirtualApplianceUndeployMonitor} function.
+ * 
+ * @author Serafin Sedano
+ */
+@Test(groups = "unit", testName = "VirtualApplianceUndeployMonitorTest")
+public class VirtualApplianceUndeployMonitorTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullArgument()
+    {
+        Function<VirtualAppliance, MonitorStatus> function = new VirtualApplianceUndeployMonitor();
+        function.apply(null);
+    }
+
+    public void testReturnDone()
+    {
+        VirtualApplianceState[] states = {VirtualApplianceState.NOT_DEPLOYED};
+
+        checkStatesReturn(new MockVirtualAppliance(), new VirtualApplianceUndeployMonitor(),
+            states, MonitorStatus.DONE);
+    }
+
+    public void testReturnFail()
+    {
+        VirtualApplianceState[] states =
+            {VirtualApplianceState.DEPLOYED, VirtualApplianceState.NEEDS_SYNC,
+            VirtualApplianceState.UNKNOWN};
+
+        checkStatesReturn(new MockVirtualAppliance(), new VirtualApplianceUndeployMonitor(),
+            states, MonitorStatus.FAILED);
+    }
+
+    public void testReturnContinue()
+    {
+        VirtualApplianceState[] states = {VirtualApplianceState.LOCKED};
+
+        checkStatesReturn(new MockVirtualAppliance(), new VirtualApplianceUndeployMonitor(),
+            states, MonitorStatus.CONTINUE);
+
+        checkStatesReturn(new MockVirtualApplianceFailing(), new VirtualApplianceUndeployMonitor(),
+            states, MonitorStatus.CONTINUE);
+    }
+
+    private void checkStatesReturn(final MockVirtualAppliance vapp,
+        final Function<VirtualAppliance, MonitorStatus> function,
+        final VirtualApplianceState[] states, final MonitorStatus expectedStatus)
+    {
+        for (VirtualApplianceState state : states)
+        {
+            vapp.setState(state);
+            assertEquals(function.apply(vapp), expectedStatus);
+        }
+    }
+
+    private static class MockVirtualAppliance extends VirtualAppliance
+    {
+        private VirtualApplianceState state;
+
+        @SuppressWarnings("unchecked")
+        public MockVirtualAppliance()
+        {
+            super(EasyMock.createMock(RestContext.class), new VirtualApplianceDto());
+        }
+
+        @Override
+        public VirtualApplianceState getState()
+        {
+            return state;
+        }
+
+        public void setState(final VirtualApplianceState state)
+        {
+            this.state = state;
+        }
+    }
+
+    private static class MockVirtualApplianceFailing extends MockVirtualAppliance
+    {
+        @Override
+        public VirtualApplianceState getState()
+        {
+            throw new RuntimeException("This mock class always fails to get the state");
+        }
+
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineDeployMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineDeployMonitorTest.java
new file mode 100644
index 0000000..2f0d08d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineDeployMonitorTest.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link VirtualMachineDeployMonitor} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "VirtualMachineDeployMonitorTest")
+public class VirtualMachineDeployMonitorTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullArgument()
+    {
+        Function<VirtualMachine, MonitorStatus> function = new VirtualMachineDeployMonitor();
+        function.apply(null);
+    }
+
+    public void testReturnDone()
+    {
+        VirtualMachineState[] states = {VirtualMachineState.ON};
+
+        checkStatesReturn(new MockVirtualMachine(), new VirtualMachineDeployMonitor(), states,
+            MonitorStatus.DONE);
+    }
+
+    public void testReturnFail()
+    {
+        VirtualMachineState[] states =
+            {VirtualMachineState.NOT_ALLOCATED, VirtualMachineState.UNKNOWN};
+
+        checkStatesReturn(new MockVirtualMachine(), new VirtualMachineDeployMonitor(), states,
+            MonitorStatus.FAILED);
+    }
+
+    public void testReturnContinue()
+    {
+        VirtualMachineState[] states =
+            {VirtualMachineState.ALLOCATED, VirtualMachineState.CONFIGURED,
+            VirtualMachineState.LOCKED, VirtualMachineState.OFF, VirtualMachineState.PAUSED};
+
+        checkStatesReturn(new MockVirtualMachine(), new VirtualMachineDeployMonitor(), states,
+            MonitorStatus.CONTINUE);
+
+        checkStatesReturn(new MockVirtualMachineFailing(), new VirtualMachineDeployMonitor(),
+            states, MonitorStatus.CONTINUE);
+    }
+
+    private void checkStatesReturn(final MockVirtualMachine vm,
+        final Function<VirtualMachine, MonitorStatus> function, final VirtualMachineState[] states,
+        final MonitorStatus expectedStatus)
+    {
+        for (VirtualMachineState state : states)
+        {
+            vm.setState(state);
+            assertEquals(function.apply(vm), expectedStatus);
+        }
+    }
+
+    private static class MockVirtualMachine extends VirtualMachine
+    {
+        private VirtualMachineState state;
+
+        @SuppressWarnings("unchecked")
+        public MockVirtualMachine()
+        {
+            super(EasyMock.createMock(RestContext.class), new VirtualMachineWithNodeExtendedDto());
+        }
+
+        @Override
+        public VirtualMachineState getState()
+        {
+            return state;
+        }
+
+        public void setState(final VirtualMachineState state)
+        {
+            this.state = state;
+        }
+    }
+
+    private static class MockVirtualMachineFailing extends MockVirtualMachine
+    {
+        @Override
+        public VirtualMachineState getState()
+        {
+            throw new RuntimeException("This mock class always fails to get the state");
+        }
+
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineStateMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineStateMonitorTest.java
new file mode 100644
index 0000000..0ec4307
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineStateMonitorTest.java
@@ -0,0 +1,120 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link VirtualMachineStateMonitor} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "VirtualMachineStateMonitorTest")
+public class VirtualMachineStateMonitorTest
+{
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullState()
+    {
+        new VirtualMachineStateMonitor(null);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullArgument()
+    {
+        Function<VirtualMachine, MonitorStatus> function =
+            new VirtualMachineStateMonitor(VirtualMachineState.ON);
+        function.apply(null);
+    }
+
+    public void testReturnDone()
+    {
+        VirtualMachineState[] states = {VirtualMachineState.ON};
+
+        checkStatesReturn(new MockVirtualMachine(),
+            new VirtualMachineStateMonitor(VirtualMachineState.ON), states, MonitorStatus.DONE);
+    }
+
+    public void testReturnContinue()
+    {
+        VirtualMachineState[] states =
+            {VirtualMachineState.ALLOCATED, VirtualMachineState.CONFIGURED,
+            VirtualMachineState.LOCKED, VirtualMachineState.OFF, VirtualMachineState.PAUSED,
+            VirtualMachineState.NOT_ALLOCATED, VirtualMachineState.UNKNOWN};
+
+        checkStatesReturn(new MockVirtualMachine(),
+            new VirtualMachineStateMonitor(VirtualMachineState.ON), states, MonitorStatus.CONTINUE);
+
+        checkStatesReturn(new MockVirtualMachineFailing(),
+            new VirtualMachineStateMonitor(VirtualMachineState.ON), states, MonitorStatus.CONTINUE);
+    }
+
+    private void checkStatesReturn(final MockVirtualMachine vm,
+        final Function<VirtualMachine, MonitorStatus> function, final VirtualMachineState[] states,
+        final MonitorStatus expectedStatus)
+    {
+        for (VirtualMachineState state : states)
+        {
+            vm.setState(state);
+            assertEquals(function.apply(vm), expectedStatus);
+        }
+    }
+
+    private static class MockVirtualMachine extends VirtualMachine
+    {
+        private VirtualMachineState state;
+
+        @SuppressWarnings("unchecked")
+        public MockVirtualMachine()
+        {
+            super(EasyMock.createMock(RestContext.class), new VirtualMachineWithNodeExtendedDto());
+        }
+
+        @Override
+        public VirtualMachineState getState()
+        {
+            return state;
+        }
+
+        public void setState(final VirtualMachineState state)
+        {
+            this.state = state;
+        }
+    }
+
+    private static class MockVirtualMachineFailing extends MockVirtualMachine
+    {
+        @Override
+        public VirtualMachineState getState()
+        {
+            throw new RuntimeException("This mock class always fails to get the state");
+        }
+
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineUndeployMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineUndeployMonitorTest.java
new file mode 100644
index 0000000..e5a2dba
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/VirtualMachineUndeployMonitorTest.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.functions;
+
+import static org.testng.Assert.assertEquals;
+
+import org.easymock.EasyMock;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.monitor.MonitorStatus;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.Test;
+
+import com.abiquo.server.core.cloud.VirtualMachineState;
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.google.common.base.Function;
+
+/**
+ * Unit tests for the {@link VirtualMachineUndeployMonitor} function.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "VirtualMachineUndeployMonitorTest")
+public class VirtualMachineUndeployMonitorTest
+{
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void testInvalidNullArgument()
+    {
+        Function<VirtualMachine, MonitorStatus> function = new VirtualMachineUndeployMonitor();
+        function.apply(null);
+    }
+
+    public void testReturnDone()
+    {
+        VirtualMachineState[] states = {VirtualMachineState.NOT_ALLOCATED};
+
+        checkStatesReturn(new MockVirtualMachine(), new VirtualMachineUndeployMonitor(), states,
+            MonitorStatus.DONE);
+    }
+
+    public void testReturnFail()
+    {
+        VirtualMachineState[] states =
+            {VirtualMachineState.ON, VirtualMachineState.CONFIGURED, VirtualMachineState.OFF,
+            VirtualMachineState.PAUSED, VirtualMachineState.UNKNOWN};
+
+        checkStatesReturn(new MockVirtualMachine(), new VirtualMachineUndeployMonitor(), states,
+            MonitorStatus.FAILED);
+    }
+
+    public void testReturnContinue()
+    {
+        VirtualMachineState[] states = {VirtualMachineState.ALLOCATED, VirtualMachineState.LOCKED};
+
+        checkStatesReturn(new MockVirtualMachine(), new VirtualMachineUndeployMonitor(), states,
+            MonitorStatus.CONTINUE);
+
+        checkStatesReturn(new MockVirtualMachineFailing(), new VirtualMachineUndeployMonitor(),
+            states, MonitorStatus.CONTINUE);
+    }
+
+    private void checkStatesReturn(final MockVirtualMachine vm,
+        final Function<VirtualMachine, MonitorStatus> function, final VirtualMachineState[] states,
+        final MonitorStatus expectedStatus)
+    {
+        for (VirtualMachineState state : states)
+        {
+            vm.setState(state);
+            assertEquals(function.apply(vm), expectedStatus);
+        }
+    }
+
+    private static class MockVirtualMachine extends VirtualMachine
+    {
+        private VirtualMachineState state;
+
+        @SuppressWarnings("unchecked")
+        public MockVirtualMachine()
+        {
+            super(EasyMock.createMock(RestContext.class), new VirtualMachineWithNodeExtendedDto());
+        }
+
+        @Override
+        public VirtualMachineState getState()
+        {
+            return state;
+        }
+
+        public void setState(final VirtualMachineState state)
+        {
+            this.state = state;
+        }
+    }
+
+    private static class MockVirtualMachineFailing extends MockVirtualMachine
+    {
+        @Override
+        public VirtualMachineState getState()
+        {
+            throw new RuntimeException("This mock class always fails to get the state");
+        }
+
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitorTest.java
new file mode 100644
index 0000000..729148a
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitorTest.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.internal;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.internal.BaseInjectionTest;
+import org.jclouds.abiquo.monitor.AsyncTaskMonitor;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BaseAsyncTaskMonitor} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BaseAsyncTaskMonitorTest")
+public class BaseAsyncTaskMonitorTest extends BaseInjectionTest
+{
+
+    public void testAllPropertiesInjected()
+    {
+        BaseAsyncTaskMonitor monitor =
+            (BaseAsyncTaskMonitor) injector.getInstance(AsyncTaskMonitor.class);
+
+        assertNotNull(monitor.taskMonitor);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseVirtualApplianceMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseVirtualApplianceMonitorTest.java
new file mode 100644
index 0000000..eb8bf9f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseVirtualApplianceMonitorTest.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.internal;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.internal.BaseInjectionTest;
+import org.jclouds.abiquo.monitor.VirtualApplianceMonitor;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BaseVirtualApplianceMonitor} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BaseVirtualApplianceMonitorTest")
+public class BaseVirtualApplianceMonitorTest extends BaseInjectionTest
+{
+
+    public void testAllPropertiesInjected()
+    {
+        BaseVirtualApplianceMonitor monitor =
+            (BaseVirtualApplianceMonitor) injector.getInstance(VirtualApplianceMonitor.class);
+
+        assertNotNull(monitor.deployMonitor);
+        assertNotNull(monitor.undeployMonitor);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseVirtualMachineMonitorTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseVirtualMachineMonitorTest.java
new file mode 100644
index 0000000..a07d75b
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/monitor/internal/BaseVirtualMachineMonitorTest.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.monitor.internal;
+
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.abiquo.internal.BaseInjectionTest;
+import org.jclouds.abiquo.monitor.VirtualMachineMonitor;
+import org.testng.annotations.Test;
+
+/**
+ * Unit tests for the {@link BaseVirtualMachineMonitor} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "BaseVirtualMachineMonitorTest")
+public class BaseVirtualMachineMonitorTest extends BaseInjectionTest
+{
+
+    public void testAllPropertiesInjected()
+    {
+        BaseVirtualMachineMonitor monitor =
+            (BaseVirtualMachineMonitor) injector.getInstance(VirtualMachineMonitor.class);
+
+        assertNotNull(monitor.deployMonitor);
+        assertNotNull(monitor.undeployMonitor);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/reference/AbiquoTestConstants.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/reference/AbiquoTestConstants.java
new file mode 100644
index 0000000..0a3fcf4
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/reference/AbiquoTestConstants.java
@@ -0,0 +1,31 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.reference;
+
+/**
+ * Configuration constants and properties used in Abiquo tests.
+ * 
+ * @author Ignasi Barrera
+ */
+public interface AbiquoTestConstants
+{
+    /** The prefix for test object names. */
+    public static final String PREFIX = "JC-";
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/rest/internal/AbiquoHttpAsyncClientTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/rest/internal/AbiquoHttpAsyncClientTest.java
new file mode 100644
index 0000000..fc49bb2
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/rest/internal/AbiquoHttpAsyncClientTest.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.rest.internal;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.abiquo.features.BaseAbiquoAsyncApiTest;
+import org.jclouds.functions.IdentityFunction;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.GeneratedHttpRequest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.server.core.infrastructure.DatacentersDto;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code AbiquoHttpAsyncApi}.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "AbiquoHttpAsyncClientTest")
+public class AbiquoHttpAsyncClientTest extends BaseAbiquoAsyncApiTest<AbiquoHttpAsyncClient>
+{
+    public void testGet() throws SecurityException, NoSuchMethodException, IOException
+    {
+        RESTLink link = new RESTLink("edit", "http://foo/bar");
+        link.setType(DatacentersDto.BASE_MEDIA_TYPE);
+
+        Method method = AbiquoHttpAsyncClient.class.getMethod("get", RESTLink.class);
+        GeneratedHttpRequest request = processor.createRequest(method, link);
+
+        assertRequestLineEquals(request, "GET http://foo/bar HTTP/1.1");
+        assertNonPayloadHeadersEqual(request, "Accept: " + DatacentersDto.BASE_MEDIA_TYPE + "\n");
+        assertPayloadEquals(request, null, null, false);
+
+        assertResponseParserClassEquals(method, request, IdentityFunction.class);
+        assertSaxResponseParserClassEquals(method, null);
+        assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+        checkFilters(request);
+    }
+
+    @Override
+    protected TypeLiteral<RestAnnotationProcessor<AbiquoHttpAsyncClient>> createTypeLiteral()
+    {
+        return new TypeLiteral<RestAnnotationProcessor<AbiquoHttpAsyncClient>>()
+        {
+        };
+    }
+
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/BaseAbiquoStrategyLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/BaseAbiquoStrategyLiveApiTest.java
new file mode 100644
index 0000000..06d10f1
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/BaseAbiquoStrategyLiveApiTest.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy;
+
+import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
+import org.testng.annotations.BeforeClass;
+
+/**
+ * Base class for strategy live tests.
+ * 
+ * @author Ignasi Barrera
+ */
+public abstract class BaseAbiquoStrategyLiveApiTest extends BaseAbiquoApiLiveApiTest
+{
+    @BeforeClass(groups = "api")
+    protected abstract void setupStrategy();
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/admin/internal/ListRolesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/admin/internal/ListRolesImplLiveApiTest.java
new file mode 100644
index 0000000..9e3ec7f
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/admin/internal/ListRolesImplLiveApiTest.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.admin.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.enterprise.Role;
+import org.jclouds.abiquo.predicates.enterprise.RolePredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListRolesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListRolesImplLiveApiTest")
+public class ListRolesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListRolesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy = env.context.getUtils().getInjector().getInstance(ListRolesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<Role> roles = strategy.execute();
+        assertNotNull(roles);
+        assertTrue(size(roles) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<Role> roles = strategy.execute(RolePredicates.name("UNEXISTING"));
+        assertNotNull(roles);
+        assertEquals(size(roles), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<Role> roles = strategy.execute(RolePredicates.name(env.role.getName()));
+        assertNotNull(roles);
+        assertEquals(size(roles), 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListAttachedNicsImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListAttachedNicsImplLiveApiTest.java
new file mode 100644
index 0000000..997a73d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListAttachedNicsImplLiveApiTest.java
@@ -0,0 +1,114 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.network.ExternalIp;
+import org.jclouds.abiquo.domain.network.Ip;
+import org.jclouds.abiquo.domain.network.PrivateIp;
+import org.jclouds.abiquo.domain.network.PublicIp;
+import org.jclouds.abiquo.domain.network.UnmanagedNetwork;
+import org.jclouds.abiquo.predicates.network.IpPredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Live tests for the {@link ListAttachedNicsImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListAttachedNicsImplLiveApiTest")
+public class ListAttachedNicsImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListAttachedNicsImpl strategy;
+
+    private PrivateIp privateIp;
+
+    private ExternalIp externalIp;
+
+    private PublicIp publicIp;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy =
+            env.context.getUtils().getInjector().getInstance(ListAttachedNicsImpl.class);
+
+        privateIp = env.privateNetwork.listUnusedIps().get(0);
+        assertNotNull(privateIp);
+
+        externalIp = env.externalNetwork.listUnusedIps().get(0);
+        assertNotNull(externalIp);
+
+        publicIp = env.virtualDatacenter.listAvailablePublicIps().get(0);
+        env.virtualDatacenter.purchasePublicIp(publicIp);
+        publicIp =
+            env.virtualDatacenter.findPurchasedPublicIp(IpPredicates.<PublicIp> address(publicIp
+                .getIp()));
+        assertNotNull(publicIp);
+
+        env.virtualMachine.setNics(
+            Lists.<Ip< ? , ? >> newArrayList(privateIp, externalIp, publicIp),
+            Lists.<UnmanagedNetwork> newArrayList(env.unmanagedNetwork));
+    }
+
+    @AfterClass(groups = "api")
+    protected void tearDownStrategy()
+    {
+        env.virtualMachine.setNics(Lists.<Ip< ? , ? >> newArrayList(privateIp));
+        String address = publicIp.getIp();
+        env.virtualDatacenter.releaseePublicIp(publicIp);
+        assertNull(env.virtualDatacenter.findPurchasedPublicIp(IpPredicates
+            .<PublicIp> address(address)));
+    }
+
+    public void testExecute()
+    {
+        Iterable<Ip< ? , ? >> vapps = strategy.execute(env.virtualMachine);
+        assertNotNull(vapps);
+        assertTrue(size(vapps) == 4);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<Ip< ? , ? >> vapps =
+            strategy.execute(env.virtualMachine, IpPredicates.address("UNEXISTING"));
+        assertNotNull(vapps);
+        assertEquals(size(vapps), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<Ip< ? , ? >> vapps =
+            strategy.execute(env.virtualMachine, IpPredicates.address(publicIp.getIp()));
+        assertNotNull(vapps);
+        assertEquals(size(vapps), 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualAppliancesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualAppliancesImplLiveApiTest.java
new file mode 100644
index 0000000..faa0633
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualAppliancesImplLiveApiTest.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.cloud.VirtualAppliance;
+import org.jclouds.abiquo.predicates.cloud.VirtualAppliancePredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListVirtualAppliancesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListVirtualAppliancesImplLiveApiTest")
+public class ListVirtualAppliancesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListVirtualAppliancesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy =
+            env.context.getUtils().getInjector().getInstance(ListVirtualAppliancesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<VirtualAppliance> vapps = strategy.execute();
+        assertNotNull(vapps);
+        assertTrue(size(vapps) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<VirtualAppliance> vapps =
+            strategy.execute(VirtualAppliancePredicates.name("UNEXISTING"));
+        assertNotNull(vapps);
+        assertEquals(size(vapps), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<VirtualAppliance> vapps =
+            strategy.execute(VirtualAppliancePredicates.name(env.virtualAppliance.getName()));
+        assertNotNull(vapps);
+        assertEquals(size(vapps), 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualDatacentersImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualDatacentersImplLiveApiTest.java
new file mode 100644
index 0000000..21048f1
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualDatacentersImplLiveApiTest.java
@@ -0,0 +1,93 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.cloud.VirtualDatacenter;
+import org.jclouds.abiquo.domain.cloud.options.VirtualDatacenterOptions;
+import org.jclouds.abiquo.predicates.cloud.VirtualDatacenterPredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListVirtualDatacentersImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListVirtualDatacentersImplLiveApiTest")
+public class ListVirtualDatacentersImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListVirtualDatacentersImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy =
+            env.context.getUtils().getInjector().getInstance(ListVirtualDatacentersImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<VirtualDatacenter> vdcs = strategy.execute();
+        assertNotNull(vdcs);
+        assertTrue(size(vdcs) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<VirtualDatacenter> vdcs =
+            strategy.execute(VirtualDatacenterPredicates.name("UNEXISTING"));
+        assertNotNull(vdcs);
+        assertEquals(size(vdcs), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<VirtualDatacenter> vdcs =
+            strategy.execute(VirtualDatacenterPredicates.name(env.virtualDatacenter.getName()));
+        assertNotNull(vdcs);
+        assertEquals(size(vdcs), 1);
+    }
+
+    public void testExecutePredicateOptionsWithResults()
+    {
+        Iterable<VirtualDatacenter> vdcs =
+            strategy.execute(VirtualDatacenterOptions.builder()
+                .datacenterId(env.datacenter.getId()).enterpriseId(env.defaultEnterprise.getId())
+                .build());
+        assertNotNull(vdcs);
+        assertEquals(size(vdcs), 1);
+    }
+
+    public void testExecutePredicateOptionsWithoutResults()
+    {
+        Iterable<VirtualDatacenter> vdcs =
+            strategy.execute(VirtualDatacenterOptions.builder()
+                .enterpriseId(env.enterprise.getId()).build());
+        assertNotNull(vdcs);
+        assertEquals(size(vdcs), 0);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualMachinesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualMachinesImplLiveApiTest.java
new file mode 100644
index 0000000..c3e1afc
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/cloud/internal/ListVirtualMachinesImplLiveApiTest.java
@@ -0,0 +1,109 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.cloud.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.abiquo.predicates.cloud.VirtualMachinePredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListVirtualMachinesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListVirtualMachinesImplLiveApiTest")
+public class ListVirtualMachinesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListVirtualMachinesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy =
+            env.context.getUtils().getInjector().getInstance(ListVirtualMachinesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<VirtualMachine> vms = strategy.execute();
+        assertNotNull(vms);
+        assertTrue(size(vms) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<VirtualMachine> vms =
+            strategy.execute(VirtualMachinePredicates.internalName("UNEXISTING"));
+        assertNotNull(vms);
+        assertEquals(size(vms), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<VirtualMachine> vms =
+            strategy.execute(VirtualMachinePredicates.internalName(env.virtualMachine
+                .getInternalName()));
+        assertNotNull(vms);
+        assertEquals(size(vms), 1);
+    }
+
+    public void testExecuteWhenExceedsPagination()
+    {
+        List<VirtualMachine> vms = new ArrayList<VirtualMachine>();
+
+        // Pagination by default is set to 25 items per page, so create a few more to verify that
+        // all are returned when listing
+        int numVms = 30;
+
+        for (int i = 0; i < numVms; i++)
+        {
+            VirtualMachine vm =
+                VirtualMachine.Builder.fromVirtualMachine(env.virtualMachine).build();
+            vm.save();
+            vms.add(vm);
+        }
+
+        try
+        {
+            Iterable<VirtualMachine> all = strategy.execute();
+
+            assertNotNull(all);
+            assertTrue(size(all) >= numVms);
+        }
+        finally
+        {
+            for (VirtualMachine vm : vms)
+            {
+                vm.delete();
+            }
+        }
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListCategoriesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListCategoriesImplLiveApiTest.java
new file mode 100644
index 0000000..ca68a97
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListCategoriesImplLiveApiTest.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.config.Category;
+import org.jclouds.abiquo.predicates.config.CategoryPredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+
+/**
+ * Live tests for the {@link ListPropertiesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "ListCategoriesImplLiveApiTest")
+public class ListCategoriesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListCategoriesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy = env.context.getUtils().getInjector().getInstance(ListCategoriesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<Category> categories = strategy.execute();
+        assertNotNull(categories);
+        assertTrue(size(categories) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<Category> categories =
+            strategy.execute(CategoryPredicates.name("Unexisting category"));
+        assertNotNull(categories);
+        assertEquals(size(categories), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<Category> categories =
+            strategy.execute(CategoryPredicates.name("Applications servers"));
+        assertNotNull(categories);
+        assertEquals(size(categories), 1);
+    }
+
+    public void testExecuteNotPredicateWithResults()
+    {
+        Iterable<Category> categories =
+            strategy.execute(Predicates.not(CategoryPredicates.name("Applications servers")));
+
+        Iterable<Category> allProperties = strategy.execute();
+
+        assertNotNull(categories);
+        assertNotNull(allProperties);
+        assertEquals(size(categories), size(allProperties) - 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListLicensesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListLicensesImplLiveApiTest.java
new file mode 100644
index 0000000..d1e0676
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListLicensesImplLiveApiTest.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.config.License;
+import org.jclouds.abiquo.domain.config.options.LicenseOptions;
+import org.jclouds.abiquo.predicates.config.LicensePredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListLicenseImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListLicensesImplLiveApiTest")
+public class ListLicensesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListLicensesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy = env.context.getUtils().getInjector().getInstance(ListLicensesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<License> licenses = strategy.execute();
+        assertNotNull(licenses);
+        assertTrue(size(licenses) > 0);
+    }
+
+    public void testExecuteInactive()
+    {
+        LicenseOptions options = LicenseOptions.builder().inactive(true).build();
+
+        Iterable<License> licenses = strategy.execute(options);
+        assertNotNull(licenses);
+        assertTrue(size(licenses) == 1);
+    }
+
+    public void testExecuteActive()
+    {
+        LicenseOptions options = LicenseOptions.builder().active(true).build();
+
+        Iterable<License> licenses = strategy.execute(options);
+        assertNotNull(licenses);
+        assertTrue(size(licenses) >= 1);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<License> licenses = strategy.execute(LicensePredicates.customer("FAIL"));
+        assertNotNull(licenses);
+        assertEquals(size(licenses), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<License> licenses =
+            strategy.execute(LicensePredicates.code(env.license.getCode()));
+        assertNotNull(licenses);
+        assertEquals(size(licenses), 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListPrivilegesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListPrivilegesImplLiveApiTest.java
new file mode 100644
index 0000000..f379f6c
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListPrivilegesImplLiveApiTest.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.config.Privilege;
+import org.jclouds.abiquo.predicates.config.PrivilegePredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+
+/**
+ * Live tests for the {@link ListPrivilegesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListPrivilegesImplLiveApiTest")
+public class ListPrivilegesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListPrivilegesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy = env.context.getUtils().getInjector().getInstance(ListPrivilegesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<Privilege> privileges = strategy.execute();
+        assertNotNull(privileges);
+        assertTrue(size(privileges) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<Privilege> privileges =
+            strategy.execute(PrivilegePredicates.name("Destroy the universe"));
+        assertNotNull(privileges);
+        assertEquals(size(privileges), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<Privilege> privileges =
+            strategy.execute(PrivilegePredicates.name("USERS_MANAGE_USERS"));
+        assertNotNull(privileges);
+        assertEquals(size(privileges), 1);
+    }
+
+    public void testExecuteNotPredicateWithResults()
+    {
+        Iterable<Privilege> privileges =
+            strategy.execute(Predicates.not(PrivilegePredicates.name("USERS_MANAGE_USERS")));
+
+        Iterable<Privilege> allPrivileges = strategy.execute();
+
+        assertNotNull(privileges);
+        assertNotNull(allPrivileges);
+        assertEquals(size(privileges), size(allPrivileges) - 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListPropertiesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListPropertiesImplLiveApiTest.java
new file mode 100644
index 0000000..26eb511
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/config/internal/ListPropertiesImplLiveApiTest.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.config.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.config.SystemProperty;
+import org.jclouds.abiquo.domain.config.options.PropertyOptions;
+import org.jclouds.abiquo.predicates.config.SystemPropertyPredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+
+/**
+ * Live tests for the {@link ListPropertiesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ * @author Francesc Montserrat
+ */
+@Test(groups = "api", testName = "ListPropertiesImplLiveApiTest")
+public class ListPropertiesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListPropertiesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy = env.context.getUtils().getInjector().getInstance(ListPropertiesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<SystemProperty> properties = strategy.execute();
+        assertNotNull(properties);
+        assertTrue(size(properties) > 0);
+    }
+
+    public void testExecuteWithOptions()
+    {
+        PropertyOptions options = PropertyOptions.builder().component("client").build();
+
+        Iterable<SystemProperty> properties = strategy.execute(options);
+        assertNotNull(properties);
+        assertTrue(size(properties) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<SystemProperty> properties =
+            strategy.execute(SystemPropertyPredicates.name("Cloud color"));
+        assertNotNull(properties);
+        assertEquals(size(properties), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<SystemProperty> properties =
+            strategy.execute(SystemPropertyPredicates
+                .name("client.applibrary.ovfpackagesDownloadingProgressUpdateInterval"));
+        assertNotNull(properties);
+        assertEquals(size(properties), 1);
+    }
+
+    public void testExecuteNotPredicateWithResults()
+    {
+        Iterable<SystemProperty> properties =
+            strategy.execute(Predicates.not(SystemPropertyPredicates
+                .name("client.applibrary.ovfpackagesDownloadingProgressUpdateInterval")));
+
+        Iterable<SystemProperty> allProperties = strategy.execute();
+
+        assertNotNull(properties);
+        assertNotNull(allProperties);
+        assertEquals(size(properties), size(allProperties) - 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/enterprise/internal/ListEnterprisesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/enterprise/internal/ListEnterprisesImplLiveApiTest.java
new file mode 100644
index 0000000..6175710
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/enterprise/internal/ListEnterprisesImplLiveApiTest.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.enterprise.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.enterprise.Enterprise;
+import org.jclouds.abiquo.predicates.enterprise.EnterprisePredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListEnterprisesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListEnterprisesImplLiveApiTest")
+public class ListEnterprisesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListEnterprisesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy = env.context.getUtils().getInjector().getInstance(ListEnterprisesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<Enterprise> enterprises = strategy.execute();
+        assertNotNull(enterprises);
+        assertTrue(size(enterprises) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<Enterprise> enterprises =
+            strategy.execute(EnterprisePredicates.name("UNEXISTING"));
+        assertNotNull(enterprises);
+        assertEquals(size(enterprises), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<Enterprise> enterprises =
+            strategy.execute(EnterprisePredicates.name(env.enterprise.getName()));
+        assertNotNull(enterprises);
+        assertEquals(size(enterprises), 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/enterprise/internal/ListVirtualMachineTemplatesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/enterprise/internal/ListVirtualMachineTemplatesImplLiveApiTest.java
new file mode 100644
index 0000000..3a81709
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/enterprise/internal/ListVirtualMachineTemplatesImplLiveApiTest.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.enterprise.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.abiquo.predicates.cloud.VirtualMachineTemplatePredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.jclouds.abiquo.strategy.cloud.internal.ListVirtualAppliancesImpl;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListVirtualAppliancesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListVirtualMachineTemplatesImplLiveApiTest")
+public class ListVirtualMachineTemplatesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListVirtualMachineTemplatesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy =
+            env.context.getUtils().getInjector().getInstance(ListVirtualMachineTemplatesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<VirtualMachineTemplate> templates = strategy.execute(env.defaultEnterprise);
+        assertNotNull(templates);
+        assertTrue(size(templates) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<VirtualMachineTemplate> templates =
+            strategy.execute(env.defaultEnterprise,
+                VirtualMachineTemplatePredicates.name("UNEXISTING"));
+        assertNotNull(templates);
+        assertEquals(size(templates), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<VirtualMachineTemplate> templates =
+            strategy.execute(env.defaultEnterprise,
+                VirtualMachineTemplatePredicates.name(env.template.getName()));
+        assertNotNull(templates);
+        // Repository can have multiple templates with the same name
+        assertTrue(size(templates) > 0);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListDatacentersImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListDatacentersImplLiveApiTest.java
new file mode 100644
index 0000000..33aca3a
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListDatacentersImplLiveApiTest.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.infrastructure.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.predicates.infrastructure.DatacenterPredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListDatacentersImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListDatacentersImplLiveApiTest")
+public class ListDatacentersImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListDatacentersImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy = env.context.getUtils().getInjector().getInstance(ListDatacentersImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<Datacenter> datacenters = strategy.execute();
+        assertNotNull(datacenters);
+        assertTrue(size(datacenters) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<Datacenter> datacenters =
+            strategy.execute(DatacenterPredicates.name("UNEXISTING"));
+        assertNotNull(datacenters);
+        assertEquals(size(datacenters), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<Datacenter> datacenters =
+            strategy.execute(DatacenterPredicates.name(env.datacenter.getName()));
+        assertNotNull(datacenters);
+        assertEquals(size(datacenters), 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListMachinesImplLiveApiTest.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListMachinesImplLiveApiTest.java
new file mode 100644
index 0000000..206a15d
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/strategy/infrastructure/internal/ListMachinesImplLiveApiTest.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.strategy.infrastructure.internal;
+
+import static com.google.common.collect.Iterables.size;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.abiquo.domain.infrastructure.Machine;
+import org.jclouds.abiquo.predicates.infrastructure.MachinePredicates;
+import org.jclouds.abiquo.strategy.BaseAbiquoStrategyLiveApiTest;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Live tests for the {@link ListMachinesImpl} strategy.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "api", testName = "ListMachinesImplLiveApiTest")
+public class ListMachinesImplLiveApiTest extends BaseAbiquoStrategyLiveApiTest
+{
+    private ListMachinesImpl strategy;
+
+    @Override
+    @BeforeClass(groups = "api")
+    protected void setupStrategy()
+    {
+        this.strategy = env.context.getUtils().getInjector().getInstance(ListMachinesImpl.class);
+    }
+
+    public void testExecute()
+    {
+        Iterable<Machine> machines = strategy.execute();
+        assertNotNull(machines);
+        assertTrue(size(machines) > 0);
+    }
+
+    public void testExecutePredicateWithoutResults()
+    {
+        Iterable<Machine> machines = strategy.execute(MachinePredicates.name("UNEXISTING"));
+        assertNotNull(machines);
+        assertEquals(size(machines), 0);
+    }
+
+    public void testExecutePredicateWithResults()
+    {
+        Iterable<Machine> machines =
+            strategy.execute(MachinePredicates.name(env.machine.getName()));
+        assertNotNull(machines);
+        assertEquals(size(machines), 1);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/util/Assert.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/util/Assert.java
new file mode 100644
index 0000000..e2914fb
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/util/Assert.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.util;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.jclouds.abiquo.domain.exception.AbiquoException;
+import org.jclouds.io.Payload;
+import org.jclouds.xml.XMLParser;
+import org.jclouds.xml.internal.JAXBParser;
+
+import com.abiquo.model.transport.SingleResourceTransportDto;
+import com.abiquo.model.transport.error.ErrorDto;
+
+/**
+ * Assertion utilities.
+ * 
+ * @author Ignasi Barrera
+ */
+public class Assert
+{
+    /**
+     * Assert that the exception contains the given error.
+     * 
+     * @param exception The exception.
+     * @param expectedHttpStatus The expected HTTP status code.
+     * @param expectedErrorCode The expected error code.
+     */
+    public static void assertHasError(final AbiquoException exception,
+        final Status expectedHttpStatus, final String expectedErrorCode)
+    {
+        assertEquals(exception.getHttpStatus(), expectedHttpStatus);
+        ErrorDto error = exception.findError(expectedErrorCode);
+        assertNotNull(error);
+    }
+
+    /**
+     * Assert that the given payload matches the given string.
+     * 
+     * @param payload The payload to check.
+     * @param expected The expected string.
+     * @param entityClass The entity class for the payload.
+     * @throws IOException If there is an error during serialization.
+     */
+    public static void assertPayloadEquals(final Payload payload, final String expected,
+        final Class< ? extends SingleResourceTransportDto> entityClass) throws IOException
+    {
+        // Serialize and deserialize to avoid formatting issues
+        XMLParser xml = new JAXBParser("false");
+        SingleResourceTransportDto entity = xml.fromXML(expected, entityClass);
+        String toMatch = xml.toXML(entity, entityClass);
+
+        assertEquals(payload.getRawContent(), toMatch);
+    }
+}
diff --git a/labs/abiquo/src/test/java/org/jclouds/abiquo/util/Config.java b/labs/abiquo/src/test/java/org/jclouds/abiquo/util/Config.java
new file mode 100644
index 0000000..4b438aa
--- /dev/null
+++ b/labs/abiquo/src/test/java/org/jclouds/abiquo/util/Config.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.abiquo.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Test configuration.
+ * 
+ * @author Ignasi Barrera
+ */
+public class Config
+{
+    /** The main configuration file. */
+    private static final String CONFIG_FILE = "api-live.properties";
+
+    /** The configuration properties */
+    private Properties config;
+
+    /** The singleton configuration instance. */
+    private static Config instance;
+
+    public Config(final String config)
+    {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        this.config = new Properties();
+
+        try
+        {
+            this.config.load(cl.getResourceAsStream(config));
+        }
+        catch (IOException ex)
+        {
+            throw new RuntimeException("Could not load test configuration file", ex);
+        }
+    }
+
+    public Config(final Properties config)
+    {
+        this.config = config;
+    }
+
+    public static String get(final String property)
+    {
+        return get(property, null);
+    }
+
+    public static String get(final String property, final String defaultValue)
+    {
+        if (instance == null)
+        {
+            String configFile = System.getProperty("abiquo.live.config", CONFIG_FILE);
+            instance = new Config(configFile);
+        }
+
+        return checkNotNull(instance.config.getProperty(property, defaultValue));
+    }
+
+}
diff --git a/labs/abiquo/src/test/resources/api-live.properties b/labs/abiquo/src/test/resources/api-live.properties
new file mode 100644
index 0000000..a452389
--- /dev/null
+++ b/labs/abiquo/src/test/resources/api-live.properties
@@ -0,0 +1,20 @@
+# Hypervisor configuration
+abiquo.hypervisor.type = ${abiquo.hypervisor.type}
+abiquo.hypervisor.address = ${abiquo.hypervisor.address}
+abiquo.hypervisor.user = ${abiquo.hypervisor.user}
+abiquo.hypervisor.pass = ${abiquo.hypervisor.pass}
+abiquo.hypervisor.vswitch = ${abiquo.hypervisor.vswitch}
+abiquo.hypervisor.datastore = ${abiquo.hypervisor.datastore}
+
+# Storage configuration
+abiquo.storage.type = ${abiquo.storage.type}
+abiquo.storage.address = ${abiquo.storage.address}
+abiquo.storage.pass = ${abiquo.storage.pass}
+abiquo.storage.user = ${abiquo.storage.user}
+abiquo.storage.pool = ${abiquo.storage.pool}
+
+# UCS Rack configuration
+abiquo.ucs.address = ${abiquo.ucs.address}
+abiquo.ucs.port = ${abiquo.ucs.port}
+abiquo.ucs.pass = ${abiquo.ucs.pass}
+abiquo.ucs.user = ${abiquo.ucs.user}
diff --git a/labs/abiquo/src/test/resources/filters/filters.properties b/labs/abiquo/src/test/resources/filters/filters.properties
new file mode 100644
index 0000000..8f434a8
--- /dev/null
+++ b/labs/abiquo/src/test/resources/filters/filters.properties
@@ -0,0 +1,26 @@
+# Hypervisor configuration
+# This is the Tarantino IT hypervisor.
+# Should be replaced with a dedicated ESX asap!
+
+#abiquo.hypervisor.pass=tarantino
+#abiquo.hypervisor.address=10.60.1.132
+#abiquo.hypervisor.datastore=nfs-ds
+abiquo.hypervisor.type=VMX_04
+abiquo.hypervisor.address=10.60.20.62
+abiquo.hypervisor.pass=temporal
+abiquo.hypervisor.user=root
+abiquo.hypervisor.vswitch=vSwitch0
+abiquo.hypervisor.datastore=datastore1
+
+# Storage configuration
+abiquo.storage.type=LVM
+abiquo.storage.address=10.60.12.177
+#abiquo.storage.user=
+#abiquo.storage.pass=
+abiquo.storage.pool=abiquo
+
+# UCS Rack configuration
+abiquo.ucs.address=10.60.1.45
+abiquo.ucs.port=80
+abiquo.ucs.pass=config
+abiquo.ucs.user=config
\ No newline at end of file
diff --git a/labs/abiquo/src/test/resources/filters/filters_jenkins.properties b/labs/abiquo/src/test/resources/filters/filters_jenkins.properties
new file mode 100644
index 0000000..071d53b
--- /dev/null
+++ b/labs/abiquo/src/test/resources/filters/filters_jenkins.properties
@@ -0,0 +1,26 @@
+# Hypervisor configuration
+# This is the Tarantino IT hypervisor.
+# Should be replaced with a dedicated ESX asap!
+#abiquo.hypervisor.pass=tarantino
+#abiquo.hypervisor.address=10.60.1.132
+#abiquo.hypervisor.datastore=nfs-ds
+abiquo.hypervisor.type=VMX_04
+abiquo.hypervisor.address=10.60.20.62
+abiquo.hypervisor.pass=temporal
+abiquo.hypervisor.user=root
+abiquo.hypervisor.vswitch=vSwitch0
+abiquo.hypervisor.datastore=datastore1
+
+
+# Storage configuration
+abiquo.storage.type=NEXENTA
+abiquo.storage.address=10.60.20.23
+abiquo.storage.user=admin
+abiquo.storage.pass=nexenta
+abiquo.storage.pool=abiquo
+
+# UCS Rack configuration
+abiquo.ucs.address=10.60.1.45
+abiquo.ucs.port=80
+abiquo.ucs.pass=config
+abiquo.ucs.user=config
\ No newline at end of file
diff --git a/labs/abiquo/src/test/resources/license/expired b/labs/abiquo/src/test/resources/license/expired
new file mode 100644
index 0000000..1db9f51
--- /dev/null
+++ b/labs/abiquo/src/test/resources/license/expired
@@ -0,0 +1 @@
+B9cG06GaLHhUlpD9AWxKVkZPd4qPB0OAbm2Blr4374Y6rtPhcukg4MMLNK0uWn5fnsoBSqVX8o0hwQ1I6D3zUbFBSibMaK5xIZQfZmReHf04HPPBg0ZyaPRTBoKy6dCLnWpQIKe8vLemAudZ0w4spdzYMH2jw2TImN+2vd4QDU1qmUItYMsV5Sz+e8YVEGbUVkjRjQCmIUJskVxC+sW47dokgl5Qo8hN+4I6vKgEnXFdOSRFW2cyGgpHVH4Js4hwLG+PS2LXPS4UwvISJXRF6tO7Rgg9iaObcBD/byH5jGmggtSECUtXqI70nesIbMXRHQ1aGHARqbHH3+0Znjcu5g==
\ No newline at end of file
diff --git a/labs/abiquo/src/test/resources/logback-test.xml b/labs/abiquo/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..70a88e8
--- /dev/null
+++ b/labs/abiquo/src/test/resources/logback-test.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <appender name="HEADERSFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>target/test-data/jclouds-headers.log</file>
+        <append>true</append>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>TRACE</level>
+        </filter>
+        <encoder>
+            <pattern>%date %level [%logger] \(%thread\) %msg%n</pattern>
+        </encoder>
+        <!-- Rollover at midnight each day -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>target/test-data/jclouds-headers.log.%d</fileNamePattern>
+            <maxHistory>5</maxHistory>
+        </rollingPolicy>
+    </appender>
+    <appender name="PAYLOADFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>target/test-data/jclouds-payloads.log</file>
+        <append>true</append>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>TRACE</level>
+        </filter>
+        <encoder>
+            <pattern>%date %level [%logger] \(%thread\) %msg%n</pattern>
+        </encoder>
+        <!-- Rollover at midnight each day -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>target/test-data/jclouds-payloads.log.%d</fileNamePattern>
+            <maxHistory>5</maxHistory>
+        </rollingPolicy>
+    </appender>
+    <appender name="COMPUTEFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>target/test-data/jclouds-compute.log</file>
+        <append>true</append>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>TRACE</level>
+        </filter>
+        <encoder>
+            <pattern>%date %level [%logger] \(%thread\) %msg%n</pattern>
+        </encoder>
+        <!-- Rollover at midnight each day -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>target/test-data/jclouds-compute.log.%d</fileNamePattern>
+            <maxHistory>5</maxHistory>
+        </rollingPolicy>
+    </appender>
+    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>target/test-data/jclouds.log</file>
+        <append>true</append>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>TRACE</level>
+        </filter>
+        <encoder>
+            <pattern>%date %level [%logger] \(%thread\) %msg%n</pattern>
+        </encoder>
+        <!-- Rollover at midnight each day -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>target/test-data/jclouds.log.%d</fileNamePattern>
+            <maxHistory>5</maxHistory>
+        </rollingPolicy>
+    </appender>
+    
+    <!-- ============= -->
+    <!-- Limit loggers -->
+    <!-- ============= -->
+    
+    <logger name="org.jclouds">
+        <level value="DEBUG" />
+        <appender-ref ref="FILE" />
+    </logger>
+    <logger name="jclouds.headers">
+        <level value="DEBUG" />
+        <appender-ref ref="HEADERSFILE" />
+        <appender-ref ref="PAYLOADFILE" />
+    </logger>
+    <logger name="jclouds.wire">
+        <level value="DEBUG" />
+        <appender-ref ref="PAYLOADFILE" />
+    </logger>
+    <logger name="jclouds.compute">
+        <level value="DEBUG" />
+        <appender-ref ref="COMPUTEFILE" />
+    </logger>
+
+    <!-- ===================== -->
+    <!-- Setup the root logger -->
+    <!-- ===================== -->
+    
+    <root>
+        <level value="WARN" />
+    </root>
+    
+</configuration>
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIApi.java
index 5fcd3e6..a361c1a 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIApi.java
@@ -20,6 +20,9 @@
 
 import java.util.concurrent.TimeUnit;
 
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
 import org.jclouds.concurrent.Timeout;
 import org.jclouds.rest.annotations.Delegate;
 import org.jclouds.snia.cdmi.v1.features.ContainerApi;
@@ -48,18 +51,20 @@
     * Provides synchronous access to Container Object Resource Operations.
     */
    @Delegate
-   ContainerApi getContainerApi();
+   ContainerApi getApi();
 
    /**
     * Provides synchronous access to Data Object Resource Operations.
     */
    @Delegate
-   DataApi getDataApi();
-   
+   @Path("/{containerName}")
+   DataApi getDataApiForContainer(@PathParam("containerName") String containerName);
+
    /**
     * Provides synchronous access to Data Object Resource Operations.
     */
    @Delegate
-   DataNonCDMIContentTypeApi getDataNonCDMIContentTypeApi();
+   @Path("/{containerName}")
+   DataNonCDMIContentTypeApi getDataNonCDMIContentTypeApiForContainer(@PathParam("containerName") String containerName);
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIApiMetadata.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIApiMetadata.java
index 0af9378..dd8ee87 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIApiMetadata.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIApiMetadata.java
@@ -66,14 +66,9 @@
 
       protected Builder() {
          super(CDMIApi.class, CDMIAsyncApi.class);
-                  id("cdmi")
-                  .name("SNIA CDMI API")
-                  .identityName("tenantId:user")
-                  .credentialName("password")
-                  .documentation(URI.create("http://www.snia.org/cdmi"))
-                  .version("1.0.1")
-                  .defaultEndpoint("http://localhost:8080")
-                  .defaultProperties(CDMIApiMetadata.defaultProperties())
+         id("cdmi").name("SNIA CDMI API").identityName("tenantId:user").credentialName("password")
+                  .documentation(URI.create("http://www.snia.org/cdmi")).version("1.0.1")
+                  .defaultEndpoint("http://localhost:8080").defaultProperties(CDMIApiMetadata.defaultProperties())
                   .defaultModules(ImmutableSet.<Class<? extends Module>> of(CDMIRestClientModule.class));
       }
 
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIAsyncApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIAsyncApi.java
index a23670f..8be45e5 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIAsyncApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/CDMIAsyncApi.java
@@ -18,9 +18,13 @@
  */
 package org.jclouds.snia.cdmi.v1;
 
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
 import org.jclouds.rest.annotations.Delegate;
 import org.jclouds.snia.cdmi.v1.features.ContainerAsyncApi;
 import org.jclouds.snia.cdmi.v1.features.DataAsyncApi;
+import org.jclouds.snia.cdmi.v1.features.DataNonCDMIContentTypeAsyncApi;
 import org.jclouds.snia.cdmi.v1.features.DomainAsyncApi;
 
 /**
@@ -43,18 +47,21 @@
     * Provides asynchronous access to Container Object Resource Operations.
     */
    @Delegate
-   ContainerAsyncApi getContainerApi();
+   ContainerAsyncApi getApi();
 
    /**
     * Provides asynchronous access to Data Object Resource Operations.
     */
    @Delegate
-   DataAsyncApi getDataApi();
+   @Path("/{containerName}")
+   DataAsyncApi getDataApiForContainer(@PathParam("containerName") String containerName);
 
    /**
     * Provides asynchronous access to Data Object Resource Operations.
     */
    @Delegate
-   DataAsyncApi getDataNonCDMIContentTypeApi();
-   
+   @Path("/{containerName}")
+   DataNonCDMIContentTypeAsyncApi getDataNonCDMIContentTypeApiForContainer(
+            @PathParam("containerName") String containerName);
+
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/ObjectTypes.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/ObjectTypes.java
index 17e627b..d79f33e 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/ObjectTypes.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/ObjectTypes.java
@@ -24,6 +24,6 @@
  */
 public interface ObjectTypes {
 
-	public static final String CONTAINER = "application/cdmi-container";
-	public static final String DATAOBJECT = "application/cdmi-object";
+   public static final String CONTAINER = "application/cdmi-container";
+   public static final String DATAOBJECT = "application/cdmi-object";
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/binders/BindQueryParmsToSuffix.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/binders/BindQueryParmsToSuffix.java
index d2fa4cf..3ea4fa8 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/binders/BindQueryParmsToSuffix.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/binders/BindQueryParmsToSuffix.java
@@ -20,29 +20,28 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
+
 import javax.inject.Singleton;
+
 import org.jclouds.http.HttpRequest;
 import org.jclouds.rest.Binder;
 import org.jclouds.snia.cdmi.v1.queryparams.CDMIObjectQueryParams;
 
 /**
- * This binding solves the problem jax-rs encoding ? ; : which some servers can
- * not handle
+ * This binding solves the problem jax-rs encoding ? ; : which some servers can not handle
  * 
  * @author Kenneth Nagin
  */
 @Singleton
 public class BindQueryParmsToSuffix implements Binder {
-	@SuppressWarnings("unchecked")
-	@Override
-	public <R extends HttpRequest> R bindToRequest(R request, Object input) {
-		checkArgument(
-				checkNotNull(input, "input") instanceof CDMIObjectQueryParams,
-				"this binder is only valid for CDMIObjectQueryParams!");
-		checkNotNull(request, "request");
-		String queryParams = input.toString();
-		return (R) request.toBuilder()
-				.endpoint(request.getEndpoint() + "?" + queryParams).build();
-	}
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      checkArgument(checkNotNull(input, "input") instanceof CDMIObjectQueryParams,
+               "this binder is only valid for CDMIObjectQueryParams!");
+      checkNotNull(request, "request");
+      String queryParams = input.toString();
+      return (R) request.toBuilder().endpoint(request.getEndpoint() + "?" + queryParams).build();
+   }
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/config/CDMIRestClientModule.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/config/CDMIRestClientModule.java
index 2004e8c..161951f 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/config/CDMIRestClientModule.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/config/CDMIRestClientModule.java
@@ -26,16 +26,16 @@
 import org.jclouds.http.annotation.ServerError;
 import org.jclouds.rest.ConfiguresRestClient;
 import org.jclouds.rest.config.RestClientModule;
-import org.jclouds.snia.cdmi.v1.CDMIAsyncApi;
 import org.jclouds.snia.cdmi.v1.CDMIApi;
-import org.jclouds.snia.cdmi.v1.features.ContainerAsyncApi;
+import org.jclouds.snia.cdmi.v1.CDMIAsyncApi;
 import org.jclouds.snia.cdmi.v1.features.ContainerApi;
-import org.jclouds.snia.cdmi.v1.features.DataAsyncApi;
+import org.jclouds.snia.cdmi.v1.features.ContainerAsyncApi;
 import org.jclouds.snia.cdmi.v1.features.DataApi;
+import org.jclouds.snia.cdmi.v1.features.DataAsyncApi;
 import org.jclouds.snia.cdmi.v1.features.DataNonCDMIContentTypeApi;
 import org.jclouds.snia.cdmi.v1.features.DataNonCDMIContentTypeAsyncApi;
-import org.jclouds.snia.cdmi.v1.features.DomainAsyncApi;
 import org.jclouds.snia.cdmi.v1.features.DomainApi;
+import org.jclouds.snia.cdmi.v1.features.DomainAsyncApi;
 import org.jclouds.snia.cdmi.v1.handlers.CDMIErrorHandler;
 
 import com.google.common.collect.ImmutableMap;
@@ -48,10 +48,10 @@
 @ConfiguresRestClient
 public class CDMIRestClientModule extends RestClientModule<CDMIApi, CDMIAsyncApi> {
 
-   public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder().put(
-            DomainApi.class, DomainAsyncApi.class).put(ContainerApi.class, ContainerAsyncApi.class).put(
-            DataApi.class, DataAsyncApi.class).put(
-                    DataNonCDMIContentTypeApi.class, DataNonCDMIContentTypeAsyncApi.class).build();
+   public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()
+            .put(DomainApi.class, DomainAsyncApi.class).put(ContainerApi.class, ContainerAsyncApi.class)
+            .put(DataApi.class, DataAsyncApi.class)
+            .put(DataNonCDMIContentTypeApi.class, DataNonCDMIContentTypeAsyncApi.class).build();
 
    public CDMIRestClientModule() {
       super(DELEGATE_MAP);
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/CDMIObject.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/CDMIObject.java
index a8437c0..dea0b74 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/CDMIObject.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/CDMIObject.java
@@ -42,269 +42,250 @@
  */
 public class CDMIObject {
 
-	public static Builder<?> builder() {
-		return new ConcreteBuilder();
-	}
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
 
-	public Builder<?> toBuilder() {
-		return builder().fromCDMIObject(this);
-	}
+   public Builder<?> toBuilder() {
+      return builder().fromCDMIObject(this);
+   }
 
-	private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-	}
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+   }
 
-	public static abstract class Builder<B extends Builder<B>> {
-		private String objectID;
-		private String objectType;
-		private String objectName;
-		private String parentURI;
+   public static abstract class Builder<B extends Builder<B>> {
+      private String objectID;
+      private String objectType;
+      private String objectName;
+      private String parentURI;
 
-		private Map<String, JsonBall> metadata = Maps.newHashMap();
+      private Map<String, JsonBall> metadata = Maps.newHashMap();
 
-		/**
-		 * @see DataObject#getMetadata()
-		 */
-		public B metadata(Map<String, JsonBall> metadata) {
-			this.metadata = ImmutableMap.copyOf(checkNotNull(metadata,
-					"metadata"));
-			return self();
-		}
+      /**
+       * @see DataObject#getMetadata()
+       */
+      public B metadata(Map<String, JsonBall> metadata) {
+         this.metadata = ImmutableMap.copyOf(checkNotNull(metadata, "metadata"));
+         return self();
+      }
 
-		@SuppressWarnings("unchecked")
-		protected B self() {
-			return (B) this;
-		}
+      @SuppressWarnings("unchecked")
+      protected B self() {
+         return (B) this;
+      }
 
-		/**
-		 * @see CDMIObject#getObjectID()
-		 */
-		public B objectID(String objectID) {
-			this.objectID = objectID;
-			return self();
-		}
+      /**
+       * @see CDMIObject#getObjectID()
+       */
+      public B objectID(String objectID) {
+         this.objectID = objectID;
+         return self();
+      }
 
-		/**
-		 * @see CDMIObject#getObjectType()
-		 */
-		public B objectType(String objectType) {
-			this.objectType = objectType;
-			return self();
-		}
+      /**
+       * @see CDMIObject#getObjectType()
+       */
+      public B objectType(String objectType) {
+         this.objectType = objectType;
+         return self();
+      }
 
-		/**
-		 * @see CDMIObject#getObjectName()
-		 */
-		public B objectName(String objectName) {
-			this.objectName = objectName;
-			return self();
-		}
+      /**
+       * @see CDMIObject#getObjectName()
+       */
+      public B objectName(String objectName) {
+         this.objectName = objectName;
+         return self();
+      }
 
-		/**
-		 * @see CDMIObject#getParentURI()
-		 */
-		public B parentURI(String parentURI) {
-			this.parentURI = parentURI;
-			return self();
-		}
+      /**
+       * @see CDMIObject#getParentURI()
+       */
+      public B parentURI(String parentURI) {
+         this.parentURI = parentURI;
+         return self();
+      }
 
-		public CDMIObject build() {
-			return new CDMIObject(this);
-		}
+      public CDMIObject build() {
+         return new CDMIObject(this);
+      }
 
-		protected B fromCDMIObject(CDMIObject in) {
-			return objectID(in.getObjectID()).objectType(in.getObjectType())
-					.objectName(in.getObjectName())
-					.parentURI(in.getParentURI()).metadata(in.getMetadata());
-		}
-	}
+      protected B fromCDMIObject(CDMIObject in) {
+         return objectID(in.getObjectID()).objectType(in.getObjectType()).objectName(in.getObjectName())
+                  .parentURI(in.getParentURI()).metadata(in.getMetadata());
+      }
+   }
 
-	private final String objectID;
-	private final String objectType;
-	private final String objectName;
-	private String parentURI;
-	private final Map<String, JsonBall> metadata;
-	private Map<String, String> userMetaDataIn;
-	private Map<String, String> systemMetaDataIn;
-	private List<Map<String, String>> aclMetaDataIn;
+   private final String objectID;
+   private final String objectType;
+   private final String objectName;
+   private String parentURI;
+   private final Map<String, JsonBall> metadata;
+   private Map<String, String> userMetaDataIn;
+   private Map<String, String> systemMetaDataIn;
+   private List<Map<String, String>> aclMetaDataIn;
 
-	protected CDMIObject(Builder<?> builder) {
-		this.objectID = checkNotNull(builder.objectID, "objectID");
-		this.objectType = checkNotNull(builder.objectType, "objectType");
-		this.objectName = builder.objectName;
-		this.parentURI = checkNotNull(builder.parentURI, "parentURI");
-		this.metadata = ImmutableMap.copyOf(checkNotNull(builder.metadata,
-				"metadata"));
-	}
+   protected CDMIObject(Builder<?> builder) {
+      this.objectID = checkNotNull(builder.objectID, "objectID");
+      this.objectType = checkNotNull(builder.objectType, "objectType");
+      this.objectName = builder.objectName;
+      this.parentURI = checkNotNull(builder.parentURI, "parentURI");
+      this.metadata = ImmutableMap.copyOf(checkNotNull(builder.metadata, "metadata"));
+   }
 
-	/**
-	 * Object ID of the object <br/>
-	 * Every object stored within a CDMI-compliant system shall have a globally
-	 * unique object identifier (ID) assigned at creation time. The CDMI object
-	 * ID is a string with requirements for how it is generated and how it
-	 * obtains its uniqueness. Each offering that implements CDMI is able to
-	 * produce these identifiers without conflicting with other offerings.
-	 * 
-	 * note: CDMI Servers do not always support ObjectID tags, however
-	 * downstream jclouds code does not handle null so we return a empty String
-	 * instead.
-	 */
-	public String getObjectID() {
-		return (objectID == null) ? "" : objectID;
-	}
+   /**
+    * Object ID of the object <br/>
+    * Every object stored within a CDMI-compliant system shall have a globally unique object
+    * identifier (ID) assigned at creation time. The CDMI object ID is a string with requirements
+    * for how it is generated and how it obtains its uniqueness. Each offering that implements CDMI
+    * is able to produce these identifiers without conflicting with other offerings.
+    * 
+    * note: CDMI Servers do not always support ObjectID tags, however downstream jclouds code does
+    * not handle null so we return a empty String instead.
+    */
+   public String getObjectID() {
+      return (objectID == null) ? "" : objectID;
+   }
 
-	/**
-	 * 
-	 * type of the object
-	 */
-	public String getObjectType() {
-		return objectType;
-	}
+   /**
+    * 
+    * type of the object
+    */
+   public String getObjectType() {
+      return objectType;
+   }
 
-	/**
-	 * For objects in a container, the objectName field shall be returned. For
-	 * objects not in a container (objects that are only accessible by ID), the
-	 * objectName field shall not be returned.
-	 * 
-	 * Name of the object
-	 */
-	@Nullable
-	public String getObjectName() {
-		return (objectName == null) ? "" : objectName;
-	}
+   /**
+    * For objects in a container, the objectName field shall be returned. For objects not in a
+    * container (objects that are only accessible by ID), the objectName field shall not be
+    * returned.
+    * 
+    * Name of the object
+    */
+   @Nullable
+   public String getObjectName() {
+      return (objectName == null) ? "" : objectName;
+   }
 
-	/**
-	 * 
-	 * parent URI
-	 */
-	public String getParentURI() {
-		return parentURI;
-	}
+   /**
+    * 
+    * parent URI
+    */
+   public String getParentURI() {
+      return parentURI;
+   }
 
-	/**
-	 * Metadata for the CDMI object. This field includes any user and system
-	 * metadata specified in the request body metadata field, along with storage
-	 * system metadata generated by the cloud storage system.
-	 */
-	public Map<String, JsonBall> getMetadata() {
-		return metadata;
-	}
+   /**
+    * Metadata for the CDMI object. This field includes any user and system metadata specified in
+    * the request body metadata field, along with storage system metadata generated by the cloud
+    * storage system.
+    */
+   public Map<String, JsonBall> getMetadata() {
+      return metadata;
+   }
 
-	/**
-	 * Parse Metadata for the container object from the original JsonBall.
-	 * System metadata data is prefixed with cdmi. System ACL metadata data is
-	 * prefixed with cdmi_acl
-	 * 
-	 */
-	private void parseMetadata() {
-		userMetaDataIn = new HashMap<String, String>();
-		systemMetaDataIn = new HashMap<String, String>();
-		aclMetaDataIn = new ArrayList<Map<String, String>>();
-		Iterator<String> keys = metadata.keySet().iterator();
-		while (keys.hasNext()) {
-			String key = keys.next();
-			JsonBall value = metadata.get(key);
-			if (key.startsWith("cdmi")) {
-				if (key.matches("cdmi_acl")) {
-					String[] cdmi_acl_array = value.toString().split("[{}]");
-					for (int i = 0; i < cdmi_acl_array.length; i++) {
-						if (!(cdmi_acl_array[i].startsWith("[")
-								|| cdmi_acl_array[i].startsWith("]") || cdmi_acl_array[i]
-								.startsWith(","))) {
-							HashMap<String, String> aclMap = new HashMap<String, String>();
-							String[] cdmi_acl_member = cdmi_acl_array[i]
-									.split(",");
-							for (String s : cdmi_acl_member) {
-								String cdmi_acl_key = s.substring(0,
-										s.indexOf(":"));
-								String cdmi_acl_value = s.substring(s
-										.indexOf(":") + 1);
-								cdmi_acl_value.replace('"', ' ').trim();
-								aclMap.put(cdmi_acl_key, cdmi_acl_value);
-							}
-							aclMetaDataIn.add(aclMap);
-						}
-					}
-				} else {
-					systemMetaDataIn.put(key, value.toString()
-							.replace('"', ' ').trim());
-				}
-			} else {
-				userMetaDataIn.put(key, value.toString().replace('"', ' ')
-						.trim());
-			}
-		}
-	}
+   /**
+    * Parse Metadata for the container object from the original JsonBall. System metadata data is
+    * prefixed with cdmi. System ACL metadata data is prefixed with cdmi_acl
+    * 
+    */
+   private void parseMetadata() {
+      userMetaDataIn = new HashMap<String, String>();
+      systemMetaDataIn = new HashMap<String, String>();
+      aclMetaDataIn = new ArrayList<Map<String, String>>();
+      Iterator<String> keys = metadata.keySet().iterator();
+      while (keys.hasNext()) {
+         String key = keys.next();
+         JsonBall value = metadata.get(key);
+         if (key.startsWith("cdmi")) {
+            if (key.matches("cdmi_acl")) {
+               String[] cdmi_acl_array = value.toString().split("[{}]");
+               for (int i = 0; i < cdmi_acl_array.length; i++) {
+                  if (!(cdmi_acl_array[i].startsWith("[") || cdmi_acl_array[i].startsWith("]") || cdmi_acl_array[i]
+                           .startsWith(","))) {
+                     HashMap<String, String> aclMap = new HashMap<String, String>();
+                     String[] cdmi_acl_member = cdmi_acl_array[i].split(",");
+                     for (String s : cdmi_acl_member) {
+                        String cdmi_acl_key = s.substring(0, s.indexOf(":"));
+                        String cdmi_acl_value = s.substring(s.indexOf(":") + 1);
+                        cdmi_acl_value.replace('"', ' ').trim();
+                        aclMap.put(cdmi_acl_key, cdmi_acl_value);
+                     }
+                     aclMetaDataIn.add(aclMap);
+                  }
+               }
+            } else {
+               systemMetaDataIn.put(key, value.toString().replace('"', ' ').trim());
+            }
+         } else {
+            userMetaDataIn.put(key, value.toString().replace('"', ' ').trim());
+         }
+      }
+   }
 
-	/**
-	 * Get User Metadata for the container object. This field includes any user
-	 * metadata
-	 */
-	public Map<String, String> getUserMetadata() {
-		if (userMetaDataIn == null) {
-			parseMetadata();
-		}
-		return userMetaDataIn;
-	}
+   /**
+    * Get User Metadata for the container object. This field includes any user metadata
+    */
+   public Map<String, String> getUserMetadata() {
+      if (userMetaDataIn == null) {
+         parseMetadata();
+      }
+      return userMetaDataIn;
+   }
 
-	/**
-	 * Get System Metadata for the container object excluding ACL related
-	 * metadata
-	 */
-	public Map<String, String> getSystemMetadata() {
-		if (systemMetaDataIn == null) {
-			parseMetadata();
-		}
-		return systemMetaDataIn;
-	}
+   /**
+    * Get System Metadata for the container object excluding ACL related metadata
+    */
+   public Map<String, String> getSystemMetadata() {
+      if (systemMetaDataIn == null) {
+         parseMetadata();
+      }
+      return systemMetaDataIn;
+   }
 
-	/**
-	 * Get System Metadata for the container object excluding ACL related
-	 * metadata
-	 */
-	public List<Map<String, String>> getACLMetadata() {
-		if (aclMetaDataIn == null) {
-			parseMetadata();
-		}
-		return aclMetaDataIn;
-	}
+   /**
+    * Get System Metadata for the container object excluding ACL related metadata
+    */
+   public List<Map<String, String>> getACLMetadata() {
+      if (aclMetaDataIn == null) {
+         parseMetadata();
+      }
+      return aclMetaDataIn;
+   }
 
-	@Override
-	public boolean equals(Object o) {
-		if (this == o)
-			return true;
-		if (o == null || getClass() != o.getClass())
-			return false;
-		CDMIObject that = CDMIObject.class.cast(o);
-		return equal(this.objectID, that.objectID)
-				&& equal(this.objectName, that.objectName)
-				&& equal(this.objectType, that.objectType)
-				&& equal(this.parentURI, that.parentURI)
-				&& equal(this.metadata, that.metadata);
-	}
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (o == null || getClass() != o.getClass())
+         return false;
+      CDMIObject that = CDMIObject.class.cast(o);
+      return equal(this.objectID, that.objectID) && equal(this.objectName, that.objectName)
+               && equal(this.objectType, that.objectType) && equal(this.parentURI, that.parentURI)
+               && equal(this.metadata, that.metadata);
+   }
 
-	public boolean clone(Object o) {
-		if (this == o)
-			return false;
-		if (o == null || getClass() != o.getClass())
-			return false;
-		CDMIObject that = CDMIObject.class.cast(o);
-		return equal(this.objectType, that.objectType);
-	}
+   public boolean clone(Object o) {
+      if (this == o)
+         return false;
+      if (o == null || getClass() != o.getClass())
+         return false;
+      CDMIObject that = CDMIObject.class.cast(o);
+      return equal(this.objectType, that.objectType);
+   }
 
-	@Override
-	public int hashCode() {
-		return Objects.hashCode(objectID, objectName, objectType, parentURI,
-				metadata);
-	}
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(objectID, objectName, objectType, parentURI, metadata);
+   }
 
-	@Override
-	public String toString() {
-		return string().toString();
-	}
+   @Override
+   public String toString() {
+      return string().toString();
+   }
 
-	protected ToStringHelper string() {
-		return Objects.toStringHelper("").add("objectID", objectID)
-				.add("objectName", objectName).add("objectType", objectType)
-				.add("parentURI", parentURI).add("metadata", metadata);
-	}
+   protected ToStringHelper string() {
+      return Objects.toStringHelper("").add("objectID", objectID).add("objectName", objectName)
+               .add("objectType", objectType).add("parentURI", parentURI).add("metadata", metadata);
+   }
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/Container.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/Container.java
index 21dee5e..852a34a 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/Container.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/Container.java
@@ -33,87 +33,80 @@
  */
 public class Container extends CDMIObject {
 
-	public static Builder<?> builder() {
-		return new ConcreteBuilder();
-	}
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
 
-	@Override
-	public Builder<?> toBuilder() {
-		return builder().fromContainer(this);
-	}
+   @Override
+   public Builder<?> toBuilder() {
+      return builder().fromContainer(this);
+   }
 
-	public static class Builder<B extends Builder<B>> extends
-			CDMIObject.Builder<B> {
+   public static class Builder<B extends Builder<B>> extends CDMIObject.Builder<B> {
 
-		private Set<String> children = ImmutableSet.of();
+      private Set<String> children = ImmutableSet.of();
 
-		/**
-		 * @see Container#getChildren()
-		 */
-		public B children(String... children) {
-			return children(ImmutableSet.copyOf(checkNotNull(children,
-					"children")));
-		}
+      /**
+       * @see Container#getChildren()
+       */
+      public B children(String... children) {
+         return children(ImmutableSet.copyOf(checkNotNull(children, "children")));
+      }
 
-		/**
-		 * @see Container#getChildren()
-		 */
-		public B children(Set<String> children) {
-			this.children = ImmutableSet.copyOf(checkNotNull(children,
-					"children"));
-			return self();
-		}
+      /**
+       * @see Container#getChildren()
+       */
+      public B children(Set<String> children) {
+         this.children = ImmutableSet.copyOf(checkNotNull(children, "children"));
+         return self();
+      }
 
+      @Override
+      public Container build() {
+         return new Container(this);
+      }
 
-		@Override
-		public Container build() {
-			return new Container(this);
-		}
+      public B fromContainer(Container in) {
+         return fromCDMIObject(in).children(in.getChildren());
+         // .metadata(in.getMetadata());
+      }
+   }
 
-		public B fromContainer(Container in) {
-			return fromCDMIObject(in).children(in.getChildren());
-			// .metadata(in.getMetadata());
-		}
-	}
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+   }
 
-	private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-	}
+   private final Set<String> children;
 
-	private final Set<String> children;
+   protected Container(Builder<?> builder) {
+      super(builder);
+      this.children = ImmutableSet.copyOf(checkNotNull(builder.children, "children"));
+   }
 
-	protected Container(Builder<?> builder) {
-		super(builder);
-		this.children = ImmutableSet.copyOf(checkNotNull(builder.children,
-				"children"));
-	}
+   /**
+    * Names of the children objects in the container object. Child container objects end with "/".
+    */
+   public Set<String> getChildren() {
+      return children;
+   }
 
-	/**
-	 * Names of the children objects in the container object. Child container
-	 * objects end with "/".
-	 */
-	public Set<String> getChildren() {
-		return children;
-	}
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (o == null || getClass() != o.getClass())
+         return false;
+      Container that = Container.class.cast(o);
+      return super.equals(that) && equal(this.children, that.children);
+   }
 
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(super.hashCode(), children);
+   }
 
-	@Override
-	public boolean equals(Object o) {
-		if (this == o)
-			return true;
-		if (o == null || getClass() != o.getClass())
-			return false;
-		Container that = Container.class.cast(o);
-		return super.equals(that) && equal(this.children, that.children);
-	}
-
-	@Override
-	public int hashCode() {
-		return Objects.hashCode(super.hashCode(), children);
-	}
-
-	@Override
-	public ToStringHelper string() {
-		return super.string().add("children", children);
-	}
+   @Override
+   public ToStringHelper string() {
+      return super.string().add("children", children);
+   }
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/DataObject.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/DataObject.java
index f78ac12..855e500 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/DataObject.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/domain/DataObject.java
@@ -39,161 +39,155 @@
  */
 public class DataObject extends CDMIObject {
 
-	public static Builder<?> builder() {
-		return new ConcreteBuilder();
-	}
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
 
-	@Override
-	public Builder<?> toBuilder() {
-		return builder().fromDataObject(this);
-	}
+   @Override
+   public Builder<?> toBuilder() {
+      return builder().fromDataObject(this);
+   }
 
-	public static class Builder<B extends Builder<B>> extends
-			CDMIObject.Builder<B> {
-		private String mimetype = new String();
-		private String value = new String();
+   public static class Builder<B extends Builder<B>> extends CDMIObject.Builder<B> {
+      private String mimetype = new String();
+      private String value = new String();
 
-		/**
-		 * @see DataObject#getMimetype()
-		 */
-		public B mimetype(String mimetype) {
-			this.mimetype = mimetype;
-			return self();
-		}
+      /**
+       * @see DataObject#getMimetype()
+       */
+      public B mimetype(String mimetype) {
+         this.mimetype = mimetype;
+         return self();
+      }
 
-		/**
-		 * @see DataObject#getValueAsString()
-		 */
-		public B value(String value) {
-			this.value = value;
-			return self();
-		}
+      /**
+       * @see DataObject#getValueAsString()
+       */
+      public B value(String value) {
+         this.value = value;
+         return self();
+      }
 
-		@Override
-		public DataObject build() {
-			return new DataObject(this);
-		}
+      @Override
+      public DataObject build() {
+         return new DataObject(this);
+      }
 
-		public B fromDataObject(DataObject in) {
-			return fromCDMIObject(in).mimetype(in.getMimetype());
-		}
-	}
+      public B fromDataObject(DataObject in) {
+         return fromCDMIObject(in).mimetype(in.getMimetype());
+      }
+   }
 
-	private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-	}
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+   }
 
-	private final String mimetype;
-	private final String value;
+   private final String mimetype;
+   private final String value;
 
-	protected DataObject(Builder<?> builder) {
-		super(builder);
-		this.mimetype = checkNotNull(builder.mimetype, "mimetype");
-		this.value = checkNotNull(builder.value, "value");
-	}
+   protected DataObject(Builder<?> builder) {
+      super(builder);
+      this.mimetype = checkNotNull(builder.mimetype, "mimetype");
+      this.value = checkNotNull(builder.value, "value");
+   }
 
-	/**
-	 * get dataObject's mimetype.
-	 */
-	public String getMimetype() {
-		return mimetype;
-	}
+   /**
+    * get dataObject's mimetype.
+    */
+   public String getMimetype() {
+      return mimetype;
+   }
 
-	/**
-	 * get dataObject's value as a String
-	 */
-	public String getValueAsString() {
-		return value;
-	}
+   /**
+    * get dataObject's value as a String
+    */
+   public String getValueAsString() {
+      return value;
+   }
 
-	/**
-	 * get dataObject's value as a InputStream value character set is
-	 * Charsets.UTF_8
-	 * 
-	 * @return value
-	 */
-	public InputSupplier<ByteArrayInputStream> getValueAsInputSupplier() {
-		return ByteStreams.newInputStreamSupplier(value.getBytes(Charsets.UTF_8));
-	}
+   /**
+    * get dataObject's value as a InputStream value character set is Charsets.UTF_8
+    * 
+    * @return value
+    */
+   public InputSupplier<ByteArrayInputStream> getValueAsInputSupplier() {
+      return ByteStreams.newInputStreamSupplier(value.getBytes(Charsets.UTF_8));
+   }
 
-	/**
-	 * get dataObject's value as a InputStream
-	 * 
-	 * @param charset
-	 *            value character set
-	 * @return value
-	 */
-	public InputSupplier<ByteArrayInputStream> getValueAsInputSupplier(Charset charset) {
-         return ByteStreams.newInputStreamSupplier(value.getBytes(charset));
-	}
+   /**
+    * get dataObject's value as a InputStream
+    * 
+    * @param charset
+    *           value character set
+    * @return value
+    */
+   public InputSupplier<ByteArrayInputStream> getValueAsInputSupplier(Charset charset) {
+      return ByteStreams.newInputStreamSupplier(value.getBytes(charset));
+   }
 
-	/**
-	 * get dataObject's value as a ByteArray value character set is
-	 * Charsets.UTF_8
-	 * 
-	 * @return value
-	 */
-	public byte[] getValueAsByteArray() {
-		return value.getBytes(Charsets.UTF_8);
-	}
+   /**
+    * get dataObject's value as a ByteArray value character set is Charsets.UTF_8
+    * 
+    * @return value
+    */
+   public byte[] getValueAsByteArray() {
+      return value.getBytes(Charsets.UTF_8);
+   }
 
-	/**
-	 * get dataObject's value as a InputStream
-	 * 
-	 * @param charset
-	 *            value character set
-	 * @return value
-	 */
-	public byte[] getValueAsByteArray(Charset charset) {
-		return value.getBytes(charset);
-	}
+   /**
+    * get dataObject's value as a InputStream
+    * 
+    * @param charset
+    *           value character set
+    * @return value
+    */
+   public byte[] getValueAsByteArray(Charset charset) {
+      return value.getBytes(charset);
+   }
 
-	/**
-	 * get dataObject's value as a File value character set is Charsets.UTF_8
-	 * 
-	 * @param destDir
-	 *            destination directory
-	 * @return value
-	 */
-	public File getValueAsFile(File destDir) throws IOException {
-		File fileOut = new File(destDir, this.getObjectName());
-		Files.copy(getValueAsInputSupplier(), fileOut);
-		return fileOut;
-	}
-	
+   /**
+    * get dataObject's value as a File value character set is Charsets.UTF_8
+    * 
+    * @param destDir
+    *           destination directory
+    * @return value
+    */
+   public File getValueAsFile(File destDir) throws IOException {
+      File fileOut = new File(destDir, this.getObjectName());
+      Files.copy(getValueAsInputSupplier(), fileOut);
+      return fileOut;
+   }
 
-	/**
-	 * get dataObject's value as a File
-	 * 
-	 * @param charset
-	 *            value character set
-	 * @return value
-	 */
-	public File getValueAsFile(File destDir, Charset charset)
-			throws IOException {
-		File fileOut = new File(destDir, this.getObjectName());
-		Files.copy(getValueAsInputSupplier(charset), fileOut);
-		return fileOut;
-	}
+   /**
+    * get dataObject's value as a File
+    * 
+    * @param charset
+    *           value character set
+    * @return value
+    */
+   public File getValueAsFile(File destDir, Charset charset) throws IOException {
+      File fileOut = new File(destDir, this.getObjectName());
+      Files.copy(getValueAsInputSupplier(charset), fileOut);
+      return fileOut;
+   }
 
-	@Override
-	public boolean equals(Object o) {
-		if (this == o)
-			return true;
-		if (o == null || getClass() != o.getClass())
-			return false;
-		DataObject that = DataObject.class.cast(o);
-		return super.equals(that) && equal(this.mimetype, that.mimetype)
-				&& equal(this.value, that.value);
-	}
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (o == null || getClass() != o.getClass())
+         return false;
+      DataObject that = DataObject.class.cast(o);
+      return super.equals(that) && equal(this.mimetype, that.mimetype) && equal(this.value, that.value);
+   }
 
-	@Override
-	public int hashCode() {
-		return Objects.hashCode(super.hashCode(), mimetype, value);
-	}
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(super.hashCode(), mimetype, value);
+   }
 
-	@Override
-	public ToStringHelper string() {
-		return super.string().add("mimetype", mimetype);
-	}
+   @Override
+   public ToStringHelper string() {
+      return super.string().add("mimetype", mimetype);
+   }
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerApi.java
index 728d99c..fe3b1ae 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerApi.java
@@ -35,80 +35,83 @@
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface ContainerApi {
 
-	/**
-	 * get CDMI Container
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @return Container
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  container = getContainer("myContainer/");
-	 *  container = getContainer("parentContainer/childContainer/");
-	 *  }
-	 *  <pre>
-	 */
-	Container getContainer(String containerName);
+   /**
+    * get CDMI Container
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @return Container
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  container = get("myContainer/");
+    *  container = get("parentContainer/childContainer/");
+    * }
+    * 
+    *         <pre>
+    */
+   Container get(String containerName);
 
-	/**
-	 * get CDMI Container
-	 * 
-	 * @param containerName
-	 * @param queryParams
-	 *            enables getting only certain fields, metadata, children range
-	 * @return Container
-	 * <pre>
-	 * Examples: 
-	 * {@code
-	 * container = getContainer("myContainer/",ContainerQueryParams.Builder.mimetype("text/plain").field("objectName"))
-	 * container = getContainer("myContainer/",ContainerQueryParams.Builder.metadata().field("objectName"))
-	 * }
-	 * </pre>
-	 * @see ContainerQueryParams 
-	 */
-	Container getContainer(String containerName,
-			ContainerQueryParams queryParams);
+   /**
+    * get CDMI Container
+    * 
+    * @param containerName
+    * @param queryParams
+    *           enables getting only certain fields, metadata, children range
+    * @return Container
+    * 
+    *         <pre>
+    * Examples: 
+    * {@code
+    * container = get("myContainer/",ContainerQueryParams.Builder.mimetype("text/plain").field("objectName"))
+    * container = get("myContainer/",ContainerQueryParams.Builder.metadata().field("objectName"))
+    * }
+    * </pre>
+    * @see ContainerQueryParams
+    */
+   Container get(String containerName, ContainerQueryParams queryParams);
 
-	/**
-	 * Create CDMI Container
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @return Container
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  container = createContainer("myContainer/");
-	 *  container = createContainer("parentContainer/childContainer/");
-	 *  }
-	 *  </pre>
-	 */
-	Container createContainer(String containerName);
+   /**
+    * Create CDMI Container
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @return Container
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  container = create("myContainer/");
+    *  container = create("parentContainer/childContainer/");
+    *  }
+    * </pre>
+    */
+   Container create(String containerName);
 
-	/**
-	 * Create CDMI Container
-	 * 
-	 * @param containerName
-	 * @param options
-	 *            enables adding metadata
-	 * @return Container
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  container = createContainer("myContainer/",CreateContainerOptions.Builder..metadata(metaDataIn));
-	 *  }
-	 *  </pre>
-	 * @see CreateContainerOptions
-	 */
-	Container createContainer(String containerName,
-			CreateContainerOptions... options);
+   /**
+    * Create CDMI Container
+    * 
+    * @param containerName
+    * @param options
+    *           enables adding metadata
+    * @return Container
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  container = create("myContainer/",CreateContainerOptions.Builder..metadata(metaDataIn));
+    *  }
+    * </pre>
+    * @see CreateContainerOptions
+    */
+   Container create(String containerName, CreateContainerOptions... options);
 
-	/**
-	 * Delete CDMI Container
-	 * 
-	 * @param containerName
-	 */
-	void deleteContainer(String containerName);
+   /**
+    * Delete CDMI Container
+    * 
+    * @param containerName
+    */
+   void delete(String containerName);
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerAsyncApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerAsyncApi.java
index 84cec5f..8e9c076 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerAsyncApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/ContainerAsyncApi.java
@@ -26,6 +26,7 @@
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
+
 import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.Headers;
@@ -39,6 +40,7 @@
 import org.jclouds.snia.cdmi.v1.filters.StripExtraAcceptHeader;
 import org.jclouds.snia.cdmi.v1.options.CreateContainerOptions;
 import org.jclouds.snia.cdmi.v1.queryparams.ContainerQueryParams;
+
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -49,115 +51,111 @@
  * @see <a href="http://www.snia.org/cdmi">api doc</a>
  */
 @SkipEncoding({ '/', '=' })
-@RequestFilters({ BasicAuthenticationAndTenantId.class,
-		StripExtraAcceptHeader.class })
+@RequestFilters({ BasicAuthenticationAndTenantId.class, StripExtraAcceptHeader.class })
 @Headers(keys = "X-CDMI-Specification-Version", values = "{jclouds.api-version}")
 public interface ContainerAsyncApi {
 
-	/**
-	 * get CDMI Container
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @return Container
-	 * 
-	 * <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  container = getContainer("myContainer/");
-	 *  container = getContainer("parentContainer/childContainer/");
-	 * }
-	 * 
-	 * <pre>
-	 */
-	@GET
-	@Consumes({ ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}")
-	ListenableFuture<Container> getContainer(
-			@PathParam("containerName") String containerName);
+   /**
+    * get CDMI Container
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @return Container
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  container = get("myContainer/");
+    *  container = get("parentContainer/childContainer/");
+    * }
+    * 
+    *         <pre>
+    */
+   @GET
+   @Consumes({ ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{containerName}")
+   ListenableFuture<Container> get(@PathParam("containerName") String containerName);
 
-	/**
-	 * get CDMI Container
-	 * 
-	 * @param containerName
-	 * @param queryParams
-	 *            enables getting only certain fields, metadata, children range
-	 * @return Container
-	 * 
-	 * <pre>
-	 * Examples: 
-	 * {@code
-	 * container = getContainer("myContainer/",ContainerQueryParams.Builder.field("parentURI").field("objectName"))
-	 * container = getContainer("myContainer/",ContainerQueryParams.Builder.metadata().field("objectName"))
-	 * }
-	 * </pre>
-	 * @see ContainerQueryParams
-	 */
-	@GET
-	@Consumes({ ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}")
-	ListenableFuture<Container> getContainer(
-			@PathParam("containerName") String containerName,
-			@BinderParam(BindQueryParmsToSuffix.class) ContainerQueryParams queryParams);
+   /**
+    * get CDMI Container
+    * 
+    * @param containerName
+    * @param queryParams
+    *           enables getting only certain fields, metadata, children range
+    * @return Container
+    * 
+    *         <pre>
+    * Examples: 
+    * {@code
+    * container = get("myContainer/",ContainerQueryParams.Builder.field("parentURI").field("objectName"))
+    * container = get("myContainer/",ContainerQueryParams.Builder.metadata().field("objectName"))
+    * }
+    * </pre>
+    * @see ContainerQueryParams
+    */
+   @GET
+   @Consumes({ ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{containerName}")
+   ListenableFuture<Container> get(@PathParam("containerName") String containerName,
+            @BinderParam(BindQueryParmsToSuffix.class) ContainerQueryParams queryParams);
 
-	/**
-	 * Create CDMI Container
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @return Container
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  container = createContainer("myContainer/");
-	 *  container = createContainer("parentContainer/childContainer/");
-	 *  }
-	 *  </pre>
-	 */
-	@PUT
-	@Consumes({ ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
-	@Produces({ ObjectTypes.CONTAINER })
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}")
-	ListenableFuture<Container> createContainer(
-			@PathParam("containerName") String containerName);
+   /**
+    * Create CDMI Container
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @return Container
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  container = create("myContainer/");
+    *  container = create("parentContainer/childContainer/");
+    *  }
+    * </pre>
+    */
+   @PUT
+   @Consumes({ ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
+   @Produces({ ObjectTypes.CONTAINER })
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{containerName}")
+   ListenableFuture<Container> create(@PathParam("containerName") String containerName);
 
-	/**
-	 * Create CDMI Container
-	 * 
-	 * @param containerName
-	 * @param options
-	 *            enables adding metadata
-	 * @return Container
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  container = createContainer("myContainer/",CreateContainerOptions.Builder..metadata(metaDataIn));
-	 *  }
-	 *  </pre>
-	 * @see CreateContainerOptions
-	 */
-	@PUT
-	@Consumes({ ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
-	@Produces({ ObjectTypes.CONTAINER })
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}")
-	ListenableFuture<Container> createContainer(
-			@PathParam("containerName") String containerName,
-			CreateContainerOptions... options);
+   /**
+    * Create CDMI Container
+    * 
+    * @param containerName
+    * @param options
+    *           enables adding metadata
+    * @return Container
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  container = create("myContainer/",CreateContainerOptions.Builder..metadata(metaDataIn));
+    *  }
+    * </pre>
+    * @see CreateContainerOptions
+    */
+   @PUT
+   @Consumes({ ObjectTypes.CONTAINER, MediaType.APPLICATION_JSON })
+   @Produces({ ObjectTypes.CONTAINER })
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{containerName}")
+   ListenableFuture<Container> create(@PathParam("containerName") String containerName,
+            CreateContainerOptions... options);
 
-	/**
-	 * Delete Container
-	 * 
-	 * @param containerName
-	 */
-	@DELETE
-	@Consumes(MediaType.APPLICATION_JSON)
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}")
-	ListenableFuture<Void> deleteContainer(
-			@PathParam("containerName") String containerName);
+   /**
+    * Delete Container
+    * 
+    * @param containerName
+    */
+   @DELETE
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{containerName}")
+   ListenableFuture<Void> delete(@PathParam("containerName") String containerName);
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataApi.java
index c85a945..935047e 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataApi.java
@@ -19,6 +19,7 @@
 package org.jclouds.snia.cdmi.v1.features;
 
 import java.util.concurrent.TimeUnit;
+
 import org.jclouds.concurrent.Timeout;
 import org.jclouds.snia.cdmi.v1.domain.DataObject;
 import org.jclouds.snia.cdmi.v1.options.CreateDataObjectOptions;
@@ -33,83 +34,86 @@
  */
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface DataApi {
-	/**
-	 * get CDMI Data object
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param  dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.           
-	 * @return DataObject
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  dataObject = getDataObject("myContainer/","myDataObject");
-	 *  dataObject = getDataObject("parentContainer/childContainer/","myDataObject");
-	 *  }
-	 *  <pre>
-	 */
-	DataObject getDataObject(String containerName, String dataObjectName);
-	/**
-	 * get CDMI Data object
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /. 
-	 * @param queryParams 
-	 *            enables getting only certain fields, metadata, value range
-	 * @return DataObject
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  dataObject = getContainer("myContainer/","myDataObject",ContainerQueryParams.Builder.field("parentURI").field("objectName"));
-	 *  dataObject = getContainer("myContainer/","myDataObject",ContainerQueryParams.Builder.value(0,10));
-	 *  }
-	 *  <pre>
-	 */
-	DataObject getDataObject(String containerName, String dataObjectName,
-			DataObjectQueryParams queryParams);
+   /**
+    * get CDMI Data object
+    * 
+    * 
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @return DataObject
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  dataObject = get("myDataObject");
+    *  dataObject = get("parentContainer/childContainer","myDataObject");
+    * }
+    * 
+    *         <pre>
+    */
+   DataObject get(String dataObjectName);
 
-	/**
-	 * create CDMI Data object
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /. 
-	 * @param options 
-	 *            enables defining the body i.e. metadata, mimetype, value
-	 * @return DataObject
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  dataObject = createDataObject("myContainer/",
-	 *                                "myDataObject",
-	 *                                CreateDataObjectOptions.Builder
-	 *                                                    .value(value)
-	 *                                                    .mimetype("text/plain")
-	 *                                                    .metadata(pDataObjectMetaDataIn);
-	 *  }
-	 *  <pre>
-	 */	
-	DataObject createDataObject(String containerName, String dataObjectName,
-			CreateDataObjectOptions... options);
+   /**
+    * get CDMI Data object
+    * 
+    * 
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @param queryParams
+    *           enables getting only certain fields, metadata, value range
+    * @return DataObject
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  dataObject = get("myDataObject",ContainerQueryParams.Builder.field("parentURI").field("objectName"));
+    *  dataObject = get("myDataObject",ContainerQueryParams.Builder.value(0,10));
+    * }
+    * 
+    *         <pre>
+    */
+   DataObject get(String dataObjectName, DataObjectQueryParams queryParams);
 
-	/**
-	 * delete CDMI Data object
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param  dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.           
-	 *  <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  deleteDataObject("myContainer/","myDataObject");
-	 *  }
-	 *  <pre>
-	 */
-	void deleteDataObject(String containerName, String dataObjectName);
+   /**
+    * create CDMI Data object
+    * 
+    * 
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @param options
+    *           enables defining the body i.e. metadata, mimetype, value
+    * @return DataObject
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  dataObject = create(
+    *                                "myDataObject",
+    *                                CreateDataObjectOptions.Builder
+    *                                                    .value(value)
+    *                                                    .mimetype("text/plain")
+    *                                                    .metadata(pDataObjectMetaDataIn);
+    * }
+    * 
+    *         <pre>
+    */
+   DataObject create(String dataObjectName, CreateDataObjectOptions... options);
+
+   /**
+    * delete CDMI Data object
+    * 
+    * 
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * 
+    *           <pre>
+    *  Examples: 
+    *  {@code
+    *  delete("myDataObject");
+    * }
+    * 
+    *           <pre>
+    */
+   void delete(String dataObjectName);
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataAsyncApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataAsyncApi.java
index 7ae1216..6fe8841 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataAsyncApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataAsyncApi.java
@@ -51,60 +51,48 @@
  * @see <a href="http://www.snia.org/cdmi">api doc</a>
  */
 @SkipEncoding({ '/', '=' })
-@RequestFilters({ BasicAuthenticationAndTenantId.class,
-		StripExtraAcceptHeader.class })
+@RequestFilters({ BasicAuthenticationAndTenantId.class, StripExtraAcceptHeader.class })
 @Headers(keys = "X-CDMI-Specification-Version", values = "{jclouds.api-version}")
 public interface DataAsyncApi {
-	/**
-	 * @see DataApi#getDataObject(String containerName, String dataObjectName)
-	 */
-	@GET
-	@Consumes({ ObjectTypes.DATAOBJECT, MediaType.APPLICATION_JSON })
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<DataObject> getDataObject(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName);
+   /**
+    * @see DataApi#get(String dataObjectName)
+    */
+   @GET
+   @Consumes({ ObjectTypes.DATAOBJECT, MediaType.APPLICATION_JSON })
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<DataObject> get(@PathParam("dataObjectName") String dataObjectName);
 
-	/**
-	 * @see DataApi#getDataObject(String containerName, String dataObjectName,
-	 *      DataObjectQueryParams queryParams)
-	 */
-	@GET
-	@Consumes({ ObjectTypes.DATAOBJECT, MediaType.APPLICATION_JSON })
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<DataObject> getDataObject(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName,
-			@BinderParam(BindQueryParmsToSuffix.class) DataObjectQueryParams queryParams);
+   /**
+    * @see DataApi#get(String dataObjectName, DataObjectQueryParams queryParams)
+    */
+   @GET
+   @Consumes({ ObjectTypes.DATAOBJECT, MediaType.APPLICATION_JSON })
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<DataObject> get(@PathParam("dataObjectName") String dataObjectName,
+            @BinderParam(BindQueryParmsToSuffix.class) DataObjectQueryParams queryParams);
 
-	/**
-	 * @see DataApi#createDataObject(String containerName, String
-	 *      dataObjectName, CreateDataObjectOptions... options)
-	 */
-	@PUT
-	@Consumes({ ObjectTypes.DATAOBJECT, MediaType.APPLICATION_JSON })
-	@Produces({ ObjectTypes.DATAOBJECT })
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<DataObject> createDataObject(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName,
-			CreateDataObjectOptions... options);
+   /**
+    * @see DataApi#create(String dataObjectName, CreateDataObjectOptions... options)
+    */
+   @PUT
+   @Consumes({ ObjectTypes.DATAOBJECT, MediaType.APPLICATION_JSON })
+   @Produces({ ObjectTypes.DATAOBJECT })
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<DataObject> create(@PathParam("dataObjectName") String dataObjectName,
+            CreateDataObjectOptions... options);
 
-	/**
-	 * @see DataApi#deleteDataObject(String containerName, String
-	 *      dataObjectName)
-	 */
-	@DELETE
-	@Consumes(MediaType.TEXT_PLAIN)
-	// note: MediaType.APPLICATION_JSON work also, however without consumes
-	// jclouds throws null exception
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<Void> deleteDataObject(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName);
+   /**
+    * @see DataApi#delete(String dataObjectName)
+    */
+   @DELETE
+   @Consumes(MediaType.TEXT_PLAIN)
+   // note: MediaType.APPLICATION_JSON work also, however without consumes
+   // jclouds throws null exception
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<Void> delete(@PathParam("dataObjectName") String dataObjectName);
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeApi.java
index 91b797f..593565e 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeApi.java
@@ -19,6 +19,7 @@
 package org.jclouds.snia.cdmi.v1.features;
 
 import java.util.concurrent.TimeUnit;
+
 import org.jclouds.concurrent.Timeout;
 import org.jclouds.io.Payload;
 import org.jclouds.snia.cdmi.v1.domain.DataObject;
@@ -33,172 +34,163 @@
  */
 @Timeout(duration = 600, timeUnit = TimeUnit.SECONDS)
 public interface DataNonCDMIContentTypeApi {
-	/**
-	 * get CDMI Data object
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.
-	 * @return DataObjectNonCDMIContentType
-	 * 
-	 *         <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  dataObject = getDataObject("myContainer/","myDataObject");
-	 *  dataObject = getDataObject("parentContainer/childContainer/","myDataObject");
-	 * }
-	 * 
-	 * <pre>
-	 * @see DataNonCDMIContentTypeAsyncApi#getDataObjectValue(String containerName, String dataObjectName)
-	 */
-	Payload getDataObjectValue(String containerName, String dataObjectName);
+   /**
+    * get CDMI Data object
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @return DataObjectNonCDMIContentType
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  dataObject = get("myDataObject");
+    *  dataObject = get("parentContainer/childContainer/","myDataObject");
+    * }
+    * 
+    * <pre>
+    * @see DataNonCDMIContentTypeAsyncApi#getValue(String dataObjectName)
+    */
+   Payload getValue(String dataObjectName);
 
-	/**
-	 * get CDMI Data object
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.
-	 * @param range
-	 *            a valid ranges-specifier (see RFC2616 Section 14.35.1)
-	 * @return DataObjectNonCDMIContentType
-	 * 
-	 *         <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  dataObject = getDataObject("myContainer/","myDataObject","bytes=0-10");
-	 * }
-	 * 
-	 *         <pre>
-	 */
-	Payload getDataObjectValue(String containerName, String dataObjectName,
-			String range);
+   /**
+    * get CDMI Data object
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @param range
+    *           a valid ranges-specifier (see RFC2616 Section 14.35.1)
+    * @return DataObjectNonCDMIContentType
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  dataObject = get("myDataObject","bytes=0-10");
+    * }
+    * 
+    *         <pre>
+    */
+   Payload getValue(String dataObjectName, String range);
 
-	/**
-	 * get CDMI Data object
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.
-	 * @param queryParams
-	 *            enables getting only certain fields, metadata, value range
-	 * @return DataObject
-	 * 
-	 *         <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  dataObject = getContainer("myContainer/","myDataObject",ContainerQueryParams.Builder.field("parentURI").field("objectName"));
-	 *  dataObject = getContainer("myContainer/","myDataObject",ContainerQueryParams.Builder.value(0,10));
-	 * }
-	 * 
-	 *         <pre>
-	 */
-	DataObject getDataObject(String containerName, String dataObjectName,
-			DataObjectQueryParams queryParams);
+   /**
+    * get CDMI Data object
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @param queryParams
+    *           enables getting only certain fields, metadata, value range
+    * @return DataObject
+    * 
+    *         <pre>
+    *  Examples: 
+    *  {@code
+    *  dataObject = get("myDataObject",ContainerQueryParams.Builder.field("parentURI").field("objectName"));
+    *  dataObject = get("myDataObject",ContainerQueryParams.Builder.value(0,10));
+    * }
+    * 
+    *         <pre>
+    */
+   DataObject get(String dataObjectName, DataObjectQueryParams queryParams);
 
-	/**
-	 * create CDMI Data object Non CDMI Content Type
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.
-	 * @param payload
-	 *            enables defining the body's payload i.e. file, inputStream,
-	 *            String, ByteArray
-	 * 
-	 *            <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  createDataObject("myContainer/","myDataObject",new StringPayload("value");
-	 *  createDataObject("myContainer/","myDataObject",new ByteArrayPayload(bytes);
-	 *  createDataObject("myContainer/","myDataObject",new FilePayload(myFileIn);
-	 *  createDataObject("myContainer/","myDataObject",new InputStreamPayload(is);
-	 *  
-	 *  File f = new File("yellow-flowers.jpg");
-	 *  payloadIn = new InputStreamPayload(new FileInputStream(f));
-	 *  payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(
-	 *            payloadIn.getContentMetadata().toBuilder()
-	 *            .contentType(MediaType.JPEG.toString())
-	 *            .contentLength(new Long(inFile.length()))
-	 *            .build()));
-	 *  dataNonCDMIContentTypeApi.createDataObject(containerName, f.getName(),
-	 * 					payloadIn);
-	 * }
-	 * 
-	 *            <pre>
-	 */
-	void createDataObject(String containerName, String dataObjectName,
-			Payload payload);
+   /**
+    * create CDMI Data object Non CDMI Content Type
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @param payload
+    *           enables defining the body's payload i.e. file, inputStream, String, ByteArray
+    * 
+    *           <pre>
+    *  Examples: 
+    *  {@code
+    *  create("myDataObject",new StringPayload("value");
+    *  create("myDataObject",new ByteArrayPayload(bytes);
+    *  create("myDataObject",new FilePayload(myFileIn);
+    *  create("myDataObject",new InputStreamPayload(is);
+    *  
+    *  File f = new File("yellow-flowers.jpg");
+    *  payloadIn = new InputStreamPayload(new FileInputStream(f));
+    *  payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(
+    *            payloadIn.getContentMetadata().toBuilder()
+    *            .contentType(MediaType.JPEG.toString())
+    *            .contentLength(new Long(inFile.length()))
+    *            .build()));
+    *  dataNonCDMIContentTypeApi.create(containerName, f.getName(),
+    * 					payloadIn);
+    * }
+    * 
+    *           <pre>
+    */
+   void create(String dataObjectName, Payload payload);
 
-	/**
-	 * create CDMI Data object partial Non CDMI Content Type Only part of the
-	 * object is contained in the payload and the X-CDMI-Partial header flag is
-	 * set to true
-	 * 
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.
-	 * @param payload
-	 *            enables defining the body's payload i.e. file, inputStream,
-	 *            String, ByteArray
-	 * 
-	 *            <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  createDataObjectPartial("myContainer/","myDataObject",new StringPayload("value");
-	 *  createDataObjectPartial("myContainer/","myDataObject",new ByteArrayPayload(bytes);
-	 *  createDataObjectPartial("myContainer/","myDataObject",new FilePayload(myFileIn);
-	 *  createDataObjectPartial("myContainer/","myDataObject",new InputStreamPayload(is);
-	 * }
-	 * 
-	 *            <pre>
-	 */
-	void createDataObjectPartial(String containerName, String dataObjectName,
-			Payload payload);
+   /**
+    * create CDMI Data object partial Non CDMI Content Type Only part of the object is contained in
+    * the payload and the X-CDMI-Partial header flag is set to true
+    * 
+    * 
+    * 
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @param payload
+    *           enables defining the body's payload i.e. file, inputStream, String, ByteArray
+    * 
+    *           <pre>
+    *  Examples: 
+    *  {@code
+    *  createPartial("myDataObject",new StringPayload("value");
+    *  createPartial("myDataObject",new ByteArrayPayload(bytes);
+    *  createPartial("myDataObject",new FilePayload(myFileIn);
+    *  createPartial("myDataObject",new InputStreamPayload(is);
+    * }
+    * 
+    *           <pre>
+    */
+   void createPartial(String dataObjectName, Payload payload);
 
-	/**
-	 * create CDMI Data object Non CDMI Content Type
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.
-	 * @param inputString
-	 *            simple string input
-	 * 
-	 *            <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  createDataObject("myContainer/","myDataObject",new String("value");
-	 * }
-	 * 
-	 *            <pre>
-	 */
-	void createDataObject(String containerName, String dataObjectName,
-			String inputString);
+   /**
+    * create CDMI Data object Non CDMI Content Type
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * @param inputString
+    *           simple string input
+    * 
+    *           <pre>
+    *  Examples: 
+    *  {@code
+    *  create("myDataObject",new String("value");
+    * }
+    * 
+    *           <pre>
+    */
+   void create(String dataObjectName, String inputString);
 
-	/**
-	 * delete CDMI Data object
-	 * 
-	 * @param containerName
-	 *            containerName must end with a forward slash, /.
-	 * @param dataObjectName
-	 *            dataObjectName must not end with a forward slash, /.
-	 * 
-	 *            <pre>
-	 *  Examples: 
-	 *  {@code
-	 *  deleteDataObject("myContainer/","myDataObject");
-	 * }
-	 * 
-	 *            <pre>
-	 */
-	void deleteDataObject(String containerName, String dataObjectName);
+   /**
+    * delete CDMI Data object
+    * 
+    * @param containerName
+    *           containerName must end with a forward slash, /.
+    * @param dataObjectName
+    *           dataObjectName must not end with a forward slash, /.
+    * 
+    *           <pre>
+    *  Examples: 
+    *  {@code
+    *  delete("myDataObject");
+    * }
+    * 
+    *           <pre>
+    */
+   void delete(String dataObjectName);
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeAsyncApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeAsyncApi.java
index f44630d..b58f80b 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeAsyncApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeAsyncApi.java
@@ -21,15 +21,17 @@
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
-import javax.ws.rs.HeaderParam;
 import javax.ws.rs.core.MediaType;
+
 import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.Payload;
 import org.jclouds.rest.annotations.PayloadParam;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.ResponseParser;
@@ -39,10 +41,10 @@
 import org.jclouds.snia.cdmi.v1.domain.DataObject;
 import org.jclouds.snia.cdmi.v1.filters.BasicAuthenticationAndTenantId;
 import org.jclouds.snia.cdmi.v1.filters.StripExtraAcceptHeader;
-import org.jclouds.snia.cdmi.v1.queryparams.DataObjectQueryParams;
 import org.jclouds.snia.cdmi.v1.functions.ParseObjectFromHeadersAndHttpContent;
+import org.jclouds.snia.cdmi.v1.queryparams.DataObjectQueryParams;
+
 import com.google.common.util.concurrent.ListenableFuture;
-import org.jclouds.rest.annotations.Payload;
 
 /**
  * Non CDMI Content Type Data Object Resource Operations
@@ -53,103 +55,79 @@
  * @see <a href="http://www.snia.org/cdmi">api doc</a>
  */
 @SkipEncoding({ '/', '=' })
-@RequestFilters({ BasicAuthenticationAndTenantId.class,
-		StripExtraAcceptHeader.class })
+@RequestFilters({ BasicAuthenticationAndTenantId.class, StripExtraAcceptHeader.class })
 public interface DataNonCDMIContentTypeAsyncApi {
-	/**
-	 * @see DataNonCDMIContentTypeApi#getDataObjectValue(String containerName,
-	 *      String dataObjectName)
-	 */
-	@GET
-	@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
-	@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<org.jclouds.io.Payload> getDataObjectValue(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName);
+   /**
+    * @see DataNonCDMIContentTypeApi#getValue(String dataObjectName)
+    */
+   @GET
+   @Consumes(MediaType.MEDIA_TYPE_WILDCARD)
+   @ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<org.jclouds.io.Payload> getValue(@PathParam("dataObjectName") String dataObjectName);
 
-	/**
-	 * @see DataNonCDMIContentTypeApi#getDataObjectValue(String containerName,
-	 *      String dataObjectName, String range )
-	 */
+   /**
+    * @see DataNonCDMIContentTypeApi#getValue(String dataObjectName, String range )
+    */
 
-	@GET
-	@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
-	@ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<org.jclouds.io.Payload> getDataObjectValue(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName,
-			@HeaderParam("Range") String range);
+   @GET
+   @Consumes(MediaType.MEDIA_TYPE_WILDCARD)
+   @ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<org.jclouds.io.Payload> getValue(@PathParam("dataObjectName") String dataObjectName,
+            @HeaderParam("Range") String range);
 
-	/**
-	 * @see DataNonCDMIContentTypeApi#getDataObject(String containerName, String
-	 *      dataObjectName, DataObjectQueryParams queryParams )
-	 */
-	@GET
-	@Consumes(MediaType.APPLICATION_JSON)
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<DataObject> getDataObject(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName,
-			@BinderParam(BindQueryParmsToSuffix.class) DataObjectQueryParams queryParams);
+   /**
+    * @see DataNonCDMIContentTypeApi#get(String dataObjectName, DataObjectQueryParams queryParams )
+    */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<DataObject> get(@PathParam("dataObjectName") String dataObjectName,
+            @BinderParam(BindQueryParmsToSuffix.class) DataObjectQueryParams queryParams);
 
-	/**
-	 * @see DataNonCDMIContentTypeApi#createDataObject(String containerName,
-	 *      String dataObjectName, org.jclouds.io.Payload payload )
-	 */
-	@PUT
-	@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<Void> createDataObject(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName,
-			org.jclouds.io.Payload payload);
+   /**
+    * @see DataNonCDMIContentTypeApi#create(String dataObjectName, org.jclouds.io.Payload payload )
+    */
+   @PUT
+   @Consumes(MediaType.MEDIA_TYPE_WILDCARD)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<Void> create(@PathParam("dataObjectName") String dataObjectName, org.jclouds.io.Payload payload);
 
-	/**
-	 * @see DataNonCDMIContentTypeApi#createDataObjectPartial(String
-	 *      containerName, String dataObjectName, org.jclouds.io.Payload payload
-	 *      )
-	 */
-	@PUT
-	@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	@Headers(keys = "X-CDMI-Partial", values = "true")
-	ListenableFuture<Void> createDataObjectPartial(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName,
-			org.jclouds.io.Payload payload);
+   /**
+    * @see DataNonCDMIContentTypeApi#createPartial(String dataObjectName, org.jclouds.io.Payload
+    *      payload )
+    */
+   @PUT
+   @Consumes(MediaType.MEDIA_TYPE_WILDCARD)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   @Headers(keys = "X-CDMI-Partial", values = "true")
+   ListenableFuture<Void> createPartial(@PathParam("dataObjectName") String dataObjectName,
+            org.jclouds.io.Payload payload);
 
-	/**
-	 * @see DataNonCDMIContentTypeApi#createDataObject(String containerName,
-	 *      String dataObjectName, String input )
-	 */
-	@PUT
-	@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
-	@Produces(MediaType.TEXT_PLAIN)
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	@Payload("{input}")
-	ListenableFuture<Void> createDataObject(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName,
-			@PayloadParam("input") String input);
+   /**
+    * @see DataNonCDMIContentTypeApi#create(String dataObjectName, String input )
+    */
+   @PUT
+   @Consumes(MediaType.MEDIA_TYPE_WILDCARD)
+   @Produces(MediaType.TEXT_PLAIN)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   @Payload("{input}")
+   ListenableFuture<Void> create(@PathParam("dataObjectName") String dataObjectName, @PayloadParam("input") String input);
 
-	/**
-	 * @see DataNonCDMIContentTypeApi#deleteDataObject(String containerName,
-	 *      String dataObjectName)
-	 */
-	@DELETE
-	@Consumes(MediaType.MEDIA_TYPE_WILDCARD)
-	@ExceptionParser(ReturnNullOnNotFoundOr404.class)
-	@Path("/{containerName}{dataObjectName}")
-	ListenableFuture<Void> deleteDataObject(
-			@PathParam("containerName") String containerName,
-			@PathParam("dataObjectName") String dataObjectName);
+   /**
+    * @see DataNonCDMIContentTypeApi#delete(String dataObjectName)
+    */
+   @DELETE
+   @Consumes(MediaType.MEDIA_TYPE_WILDCARD)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   @Path("/{dataObjectName}")
+   ListenableFuture<Void> delete(@PathParam("dataObjectName") String dataObjectName);
 
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DomainApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DomainApi.java
index e224e0f..f3e671a 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DomainApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DomainApi.java
@@ -32,5 +32,4 @@
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface DomainApi {
 
-
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DomainAsyncApi.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DomainAsyncApi.java
index 257a93c..78c93fd 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DomainAsyncApi.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/features/DomainAsyncApi.java
@@ -31,10 +31,9 @@
  * @author Adrian Cole
  * @see <a href="http://www.snia.org/cdmi">api doc</a>
  */
-@SkipEncoding( { '/', '=' })
-@RequestFilters( { BasicAuthenticationAndTenantId.class, StripExtraAcceptHeader.class })
-@Headers(keys="X-CDMI-Specification-Version", values = "{jclouds.api-version}")
+@SkipEncoding({ '/', '=' })
+@RequestFilters({ BasicAuthenticationAndTenantId.class, StripExtraAcceptHeader.class })
+@Headers(keys = "X-CDMI-Specification-Version", values = "{jclouds.api-version}")
 public interface DomainAsyncApi {
 
-
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/filters/StripExtraAcceptHeader.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/filters/StripExtraAcceptHeader.java
index 332ff0f..7380d17 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/filters/StripExtraAcceptHeader.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/filters/StripExtraAcceptHeader.java
@@ -34,7 +34,7 @@
  */
 @Singleton
 public class StripExtraAcceptHeader implements HttpRequestFilter {
- 
+
    @Override
    public HttpRequest filter(HttpRequest request) throws HttpException {
       return request.toBuilder().replaceHeader("Accept", request.getFirstHeaderOrNull("Accept")).build();
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/functions/ParseObjectFromHeadersAndHttpContent.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/functions/ParseObjectFromHeadersAndHttpContent.java
index 631b584..21b52e3 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/functions/ParseObjectFromHeadersAndHttpContent.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/functions/ParseObjectFromHeadersAndHttpContent.java
@@ -30,17 +30,16 @@
  * 
  * @author Kenneth Nagin
  */
-public class ParseObjectFromHeadersAndHttpContent implements
-		Function<HttpResponse, Payload>,
-		InvocationContext<ParseObjectFromHeadersAndHttpContent> {
+public class ParseObjectFromHeadersAndHttpContent implements Function<HttpResponse, Payload>,
+         InvocationContext<ParseObjectFromHeadersAndHttpContent> {
 
-	public Payload apply(HttpResponse from) {
-		Payload object = from.getPayload();
-		return object;
-	}
+   public Payload apply(HttpResponse from) {
+      Payload object = from.getPayload();
+      return object;
+   }
 
-	@Override
-	public ParseObjectFromHeadersAndHttpContent setContext(HttpRequest request) {
-		return this;
-	}
+   @Override
+   public ParseObjectFromHeadersAndHttpContent setContext(HttpRequest request) {
+      return this;
+   }
 }
diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateCDMIObjectOptions.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateCDMIObjectOptions.java
index 47ca431..7fcdfc3 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateCDMIObjectOptions.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateCDMIObjectOptions.java
@@ -8,34 +8,32 @@
 import com.google.gson.JsonObject;

 

 /**

- * Contains options supported in the REST API for the CREATE container

- * operation. <h2>

+ * Contains options supported in the REST API for the CREATE container operation. <h2>

  * 

  * @author Kenneth Nagin

  */

 public class CreateCDMIObjectOptions extends BaseHttpRequestOptions {

-	protected JsonObject jsonObjectBody = new JsonObject();

-	/**

-	 * A name-value pair to associate with the container as metadata.

-	 */

-	public CreateCDMIObjectOptions metadata(Map<String, String> metadata) {

-		JsonObject jsonObjectMetadata = new JsonObject();

-		if (metadata != null) {

-			for (Entry<String, String> entry : metadata.entrySet()) {

-				jsonObjectMetadata

-						.addProperty(entry.getKey(), entry.getValue());

-			}

-		}

-		jsonObjectBody.add("metadata", jsonObjectMetadata);

-		this.payload = jsonObjectBody.toString();

-		return this;		

-	}

+   protected JsonObject jsonObjectBody = new JsonObject();

 

-	public static class Builder {

-		public static CreateCDMIObjectOptions withMetadata(

-				Map<String, String> metadata) {

-			CreateCDMIObjectOptions options = new CreateCDMIObjectOptions();

-			return (CreateCDMIObjectOptions) options.metadata(metadata);

-		}

-	}

+   /**

+    * A name-value pair to associate with the container as metadata.

+    */

+   public CreateCDMIObjectOptions metadata(Map<String, String> metadata) {

+      JsonObject jsonObjectMetadata = new JsonObject();

+      if (metadata != null) {

+         for (Entry<String, String> entry : metadata.entrySet()) {

+            jsonObjectMetadata.addProperty(entry.getKey(), entry.getValue());

+         }

+      }

+      jsonObjectBody.add("metadata", jsonObjectMetadata);

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

+

+   public static class Builder {

+      public static CreateCDMIObjectOptions withMetadata(Map<String, String> metadata) {

+         CreateCDMIObjectOptions options = new CreateCDMIObjectOptions();

+         return (CreateCDMIObjectOptions) options.metadata(metadata);

+      }

+   }

 }

diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateContainerOptions.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateContainerOptions.java
index 39d60c7..de76fe4 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateContainerOptions.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateContainerOptions.java
@@ -8,19 +8,19 @@
  * @author Kenneth Nagin

  */

 public class CreateContainerOptions extends CreateCDMIObjectOptions {

-	/**

-	 * A name-value pair to associate with the container as metadata.

-	 */

-	public CreateContainerOptions metadata(Map<String, String> metadata) {

-		super.metadata(metadata);

-		return this;

-		

-	}

-	public static class Builder {

-		public static CreateContainerOptions metadata(

-				Map<String, String> metadata) {

-			CreateContainerOptions options = new CreateContainerOptions();

-			return (CreateContainerOptions) options.metadata(metadata);

-		}

-	}

+   /**

+    * A name-value pair to associate with the container as metadata.

+    */

+   public CreateContainerOptions metadata(Map<String, String> metadata) {

+      super.metadata(metadata);

+      return this;

+

+   }

+

+   public static class Builder {

+      public static CreateContainerOptions metadata(Map<String, String> metadata) {

+         CreateContainerOptions options = new CreateContainerOptions();

+         return (CreateContainerOptions) options.metadata(metadata);

+      }

+   }

 }

diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateDataObjectNonCDMIOptions.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateDataObjectNonCDMIOptions.java
index 5ca397f..2e05750 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateDataObjectNonCDMIOptions.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateDataObjectNonCDMIOptions.java
@@ -3,30 +3,24 @@
 import org.jclouds.http.options.BaseHttpRequestOptions;

 

 /**

- * Contains options supported in the REST API for the CREATE container

- * operation. <h2>

+ * Contains options supported in the REST API for the CREATE container operation. <h2>

  * 

  * @author Kenneth Nagin

  */

 public class CreateDataObjectNonCDMIOptions extends BaseHttpRequestOptions {

-	/**

-	 * A name-value pair to associate with the container as metadata.

-	 */

-	public CreateDataObjectNonCDMIOptions withStringPayload(String value) {

-		this.payload = value;

-		return this;

-	}

-	

+   /**

+    * A name-value pair to associate with the container as metadata.

+    */

+   public CreateDataObjectNonCDMIOptions withStringPayload(String value) {

+      this.payload = value;

+      return this;

+   }

 

-	

+   public static class Builder {

+      public static CreateDataObjectNonCDMIOptions withStringPayload(String value) {

+         CreateDataObjectNonCDMIOptions options = new CreateDataObjectNonCDMIOptions();

+         return (CreateDataObjectNonCDMIOptions) options.withStringPayload(value);

+      }

 

-	public static class Builder {

-		public static CreateDataObjectNonCDMIOptions withStringPayload(

-				String value) {

-			CreateDataObjectNonCDMIOptions options = new CreateDataObjectNonCDMIOptions();

-			return (CreateDataObjectNonCDMIOptions) options.withStringPayload(value);

-		}

-		

-

-	}

+   }

 }

diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateDataObjectOptions.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateDataObjectOptions.java
index b0738fb..3461db7 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateDataObjectOptions.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/CreateDataObjectOptions.java
@@ -3,208 +3,192 @@
 import java.io.ByteArrayInputStream;

 import java.io.DataInputStream;

 import java.io.File;

+import java.io.IOException;

 import java.io.InputStream;

 import java.io.InputStreamReader;

-import java.io.IOException;

-import java.util.Map;

-import com.google.common.base.Charsets;

 import java.nio.charset.Charset;

+import java.util.Map;

+

+import com.google.common.base.Charsets;

 import com.google.common.io.CharStreams;

 import com.google.common.io.Files;

 

 /**

- * CreateDataObjectOptions options supported in the REST API for the CREATE CDMI

- * Data Object operation. <h2>

+ * CreateDataObjectOptions options supported in the REST API for the CREATE CDMI Data Object

+ * operation. <h2>

  * 

  * @author Kenneth Nagin

  */

 public class CreateDataObjectOptions extends CreateCDMIObjectOptions {

 

-	public CreateDataObjectOptions() {

-		jsonObjectBody.addProperty("value", new String());

-	}

+   public CreateDataObjectOptions() {

+      jsonObjectBody.addProperty("value", new String());

+   }

 

-	/**

-	 * Create CDMI data object with metadata

-	 * 

-	 * @param metadata

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions metadata(Map<String, String> metadata) {

-		super.metadata(metadata);

-		return this;

-	}

+   /**

+    * Create CDMI data object with metadata

+    * 

+    * @param metadata

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions metadata(Map<String, String> metadata) {

+      super.metadata(metadata);

+      return this;

+   }

 

-	/**

-	 * Create CDMI data object with mimetype

-	 * 

-	 * @param mimetype

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions mimetype(String mimetype) {

-		jsonObjectBody.addProperty("mimetype", mimetype);

-		this.payload = jsonObjectBody.toString();

-		return this;

-	}

+   /**

+    * Create CDMI data object with mimetype

+    * 

+    * @param mimetype

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions mimetype(String mimetype) {

+      jsonObjectBody.addProperty("mimetype", mimetype);

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

 

-	/**

-	 * Create CDMI data object with value equal to empty string

-	 * 

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions value() {

-		this.payload = jsonObjectBody.toString();

-		return this;

-	}

+   /**

+    * Create CDMI data object with value equal to empty string

+    * 

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions value() {

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

 

-	/**

-	 * Create CDMI data object with String value

-	 * 

-	 * @param value

-	 *            String value

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions value(String value) {

-		jsonObjectBody.addProperty("value", (value == null) ? new String()

-				: value);

-		this.payload = jsonObjectBody.toString();

-		return this;

-	}

+   /**

+    * Create CDMI data object with String value

+    * 

+    * @param value

+    *           String value

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions value(String value) {

+      jsonObjectBody.addProperty("value", (value == null) ? new String() : value);

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

 

-	/**

-	 * Create CDMI data object with byte array value

-	 * 

-	 * @param value

-	 *            byte array value byte array is converted to a String value

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions value(byte[] value) throws IOException {

-		jsonObjectBody.addProperty("value",

-				(value == null) ? new String() : new DataInputStream(

-						new ByteArrayInputStream(value)).readUTF());

-		this.payload = jsonObjectBody.toString();

-		return this;

-	}

+   /**

+    * Create CDMI data object with byte array value

+    * 

+    * @param value

+    *           byte array value byte array is converted to a String value

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions value(byte[] value) throws IOException {

+      jsonObjectBody.addProperty("value", (value == null) ? new String() : new DataInputStream(

+               new ByteArrayInputStream(value)).readUTF());

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

 

-	/**

-	 * Create CDMI data object with file value

-	 * 

-	 * @param value

-	 *            File File is converted to a String value with charset UTF_8

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions value(File value) throws IOException {

-		jsonObjectBody.addProperty("value", (value == null) ? new String()

-				: Files.toString(value, Charsets.UTF_8));

-		this.payload = jsonObjectBody.toString();

-		return this;

-	}

+   /**

+    * Create CDMI data object with file value

+    * 

+    * @param value

+    *           File File is converted to a String value with charset UTF_8

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions value(File value) throws IOException {

+      jsonObjectBody.addProperty("value", (value == null) ? new String() : Files.toString(value, Charsets.UTF_8));

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

 

-	/**

-	 * Create CDMI data object with file value

-	 * 

-	 * @param value

-	 *            File

-	 * @param charset

-	 *            character set of file File is converted to a String value

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions value(File value, Charset charset)

-			throws IOException {

-		jsonObjectBody.addProperty("value", (value == null) ? new String()

-				: Files.toString(value, charset));

-		this.payload = jsonObjectBody.toString();

-		return this;

-	}

+   /**

+    * Create CDMI data object with file value

+    * 

+    * @param value

+    *           File

+    * @param charset

+    *           character set of file File is converted to a String value

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions value(File value, Charset charset) throws IOException {

+      jsonObjectBody.addProperty("value", (value == null) ? new String() : Files.toString(value, charset));

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

 

-	/**

-	 * Create CDMI data object with InputStream value

-	 * 

-	 * @param value

-	 *            InputSteam InputSteam is converted to a String value with

-	 *            charset UTF_8

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions value(InputStream value) throws IOException {

-		jsonObjectBody

-				.addProperty(

-						"value",

-						(value == null) ? new String() : CharStreams

-								.toString(new InputStreamReader(value,

-										Charsets.UTF_8)));

-		this.payload = jsonObjectBody.toString();

-		return this;

-	}

+   /**

+    * Create CDMI data object with InputStream value

+    * 

+    * @param value

+    *           InputSteam InputSteam is converted to a String value with charset UTF_8

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions value(InputStream value) throws IOException {

+      jsonObjectBody.addProperty("value",

+               (value == null) ? new String() : CharStreams.toString(new InputStreamReader(value, Charsets.UTF_8)));

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

 

-	/**

-	 * Create CDMI data object with InputStream value

-	 * 

-	 * @param value

-	 *            InputSteam

-	 * @param charset

-	 *            character set of input stream InputSteam is converted to a

-	 *            String value with charset UTF_8

-	 * @return CreateDataObjectOptions

-	 */

-	public CreateDataObjectOptions value(InputStream value, Charset charset)

-			throws IOException {

-		jsonObjectBody.addProperty("value", (value == null) ? new String()

-				: CharStreams.toString(new InputStreamReader(value, charset)));

-		this.payload = jsonObjectBody.toString();

-		return this;

-	}

+   /**

+    * Create CDMI data object with InputStream value

+    * 

+    * @param value

+    *           InputSteam

+    * @param charset

+    *           character set of input stream InputSteam is converted to a String value with charset

+    *           UTF_8

+    * @return CreateDataObjectOptions

+    */

+   public CreateDataObjectOptions value(InputStream value, Charset charset) throws IOException {

+      jsonObjectBody.addProperty("value",

+               (value == null) ? new String() : CharStreams.toString(new InputStreamReader(value, charset)));

+      this.payload = jsonObjectBody.toString();

+      return this;

+   }

 

-	public static class Builder {

-		public static CreateDataObjectOptions metadata(

-				Map<String, String> metadata) {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.metadata(metadata);

-		}

+   public static class Builder {

+      public static CreateDataObjectOptions metadata(Map<String, String> metadata) {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.metadata(metadata);

+      }

 

-		public static CreateDataObjectOptions mimetype(String mimetype) {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.mimetype(mimetype);

-		}

+      public static CreateDataObjectOptions mimetype(String mimetype) {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.mimetype(mimetype);

+      }

 

-		public static CreateDataObjectOptions value() {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.value();

-		}

+      public static CreateDataObjectOptions value() {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.value();

+      }

 

-		public static CreateDataObjectOptions value(String value) {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.value(value);

-		}

+      public static CreateDataObjectOptions value(String value) {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.value(value);

+      }

 

-		public static CreateDataObjectOptions value(byte[] value)

-				throws IOException {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.value(value);

-		}

+      public static CreateDataObjectOptions value(byte[] value) throws IOException {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.value(value);

+      }

 

-		public static CreateDataObjectOptions value(File value)

-				throws IOException {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.value(value);

-		}

+      public static CreateDataObjectOptions value(File value) throws IOException {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.value(value);

+      }

 

-		public static CreateDataObjectOptions value(File value, Charset charset)

-				throws IOException {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.value(value, charset);

-		}

+      public static CreateDataObjectOptions value(File value, Charset charset) throws IOException {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.value(value, charset);

+      }

 

-		public static CreateDataObjectOptions value(InputStream value)

-				throws IOException {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.value(value);

-		}

+      public static CreateDataObjectOptions value(InputStream value) throws IOException {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.value(value);

+      }

 

-		public static CreateDataObjectOptions value(InputStream value,

-				Charset charset) throws IOException {

-			CreateDataObjectOptions options = new CreateDataObjectOptions();

-			return (CreateDataObjectOptions) options.value(value, charset);

-		}

+      public static CreateDataObjectOptions value(InputStream value, Charset charset) throws IOException {

+         CreateDataObjectOptions options = new CreateDataObjectOptions();

+         return (CreateDataObjectOptions) options.value(value, charset);

+      }

 

-	}

+   }

 }

diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/GetCDMIObjectOptions.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/GetCDMIObjectOptions.java
index 0a36e15..01d5f68 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/GetCDMIObjectOptions.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/GetCDMIObjectOptions.java
@@ -3,80 +3,77 @@
 import org.jclouds.http.options.BaseHttpRequestOptions;

 

 /**

- * Optional get CDMI object options Note: We use

- * BaseHttpRequestOptions.pathSuffix to include the CDMI query parameters rather

- * than queryParam or MatrixParam because the CDMI specification is not

- * following the standard usage. This is the summary of the CDMI specification:

- * To read one or more requested fields from an existing CDMI container object,

- * one of the following requests shall be performed: 

- * GET <root URI>/<ContainerName>/<TheContainerName>/?<fieldname>;<fieldname>;... 

- * GET <root URI>/<ContainerName>/<TheContainerName>/?children:<range>;... 

- * GET <root URI>/<ContainerName>/<TheContainerName>/?metadata:<prefix>;...

+ * Optional get CDMI object options Note: We use BaseHttpRequestOptions.pathSuffix to include the

+ * CDMI query parameters rather than queryParam or MatrixParam because the CDMI specification is not

+ * following the standard usage. This is the summary of the CDMI specification: To read one or more

+ * requested fields from an existing CDMI container object, one of the following requests shall be

+ * performed: GET <root URI>/<ContainerName>/<TheContainerName>/?<fieldname>;<fieldname>;... GET

+ * <root URI>/<ContainerName>/<TheContainerName>/?children:<range>;... GET <root

+ * URI>/<ContainerName>/<TheContainerName>/?metadata:<prefix>;...

  * 

- * For example: GET /MyContainer/?parentURI;children HTTP/1.1 

- * GET /MyContainer/?childrenrange;children:0-2 HTTP/1.1

+ * For example: GET /MyContainer/?parentURI;children HTTP/1.1 GET

+ * /MyContainer/?childrenrange;children:0-2 HTTP/1.1

  * 

- * To read one or more requested fields from an existing data object, one of the

- * following requests shall be performed: 

- * GET <root URI>/<ContainerName>/<DataObjectName>?<fieldname>;<fieldname>;... 

- * GET <root URI>/<ContainerName>/<DataObjectName>?value:<range>;... 

- * GET <root URI>/<ContainerName>/<DataObjectName>?metadata:<prefix>;...

+ * To read one or more requested fields from an existing data object, one of the following requests

+ * shall be performed: GET <root URI>/<ContainerName>/<DataObjectName>?<fieldname>;<fieldname>;...

+ * GET <root URI>/<ContainerName>/<DataObjectName>?value:<range>;... GET <root

+ * URI>/<ContainerName>/<DataObjectName>?metadata:<prefix>;...

  * 

  * @author Kenneth Nagin

  */

 public class GetCDMIObjectOptions extends BaseHttpRequestOptions {

 

-	public GetCDMIObjectOptions() {

-		this.pathSuffix = "?";

-	}

+   public GetCDMIObjectOptions() {

+      this.pathSuffix = "?";

+   }

 

-	/**

-	 * Get CDMI data object's field

-	 * 

-	 * @param fieldname

-	 * @return this

-	 */

-	public GetCDMIObjectOptions field(String fieldname) {

-		this.pathSuffix = this.pathSuffix + fieldname + ";";

-		return this;

-	}

+   /**

+    * Get CDMI data object's field

+    * 

+    * @param fieldname

+    * @return this

+    */

+   public GetCDMIObjectOptions field(String fieldname) {

+      this.pathSuffix = this.pathSuffix + fieldname + ";";

+      return this;

+   }

 

-	/**

-	 * Get CDMI data object's metadata

-	 * 

-	 * @return this

-	 */

-	public GetCDMIObjectOptions metadata() {

-		this.pathSuffix = this.pathSuffix + "metadata;";

-		return this;

-	}

+   /**

+    * Get CDMI data object's metadata

+    * 

+    * @return this

+    */

+   public GetCDMIObjectOptions metadata() {

+      this.pathSuffix = this.pathSuffix + "metadata;";

+      return this;

+   }

 

-	/**

-	 * Get CDMI data object's metadata

-	 * 

-	 * @param prefix

-	 * @return this

-	 */

-	public GetCDMIObjectOptions metadata(String prefix) {

-		this.pathSuffix = this.pathSuffix + "metadata:" + prefix + ";";

-		return this;

-	}

+   /**

+    * Get CDMI data object's metadata

+    * 

+    * @param prefix

+    * @return this

+    */

+   public GetCDMIObjectOptions metadata(String prefix) {

+      this.pathSuffix = this.pathSuffix + "metadata:" + prefix + ";";

+      return this;

+   }

 

-	public static class Builder {

-		public static GetCDMIObjectOptions field(String fieldname) {

-			GetCDMIObjectOptions options = new GetCDMIObjectOptions();

-			return (GetCDMIObjectOptions) options.field(fieldname);

-		}

+   public static class Builder {

+      public static GetCDMIObjectOptions field(String fieldname) {

+         GetCDMIObjectOptions options = new GetCDMIObjectOptions();

+         return (GetCDMIObjectOptions) options.field(fieldname);

+      }

 

-		public static GetCDMIObjectOptions metadata() {

-			GetCDMIObjectOptions options = new GetCDMIObjectOptions();

-			return (GetCDMIObjectOptions) options.metadata();

-		}

+      public static GetCDMIObjectOptions metadata() {

+         GetCDMIObjectOptions options = new GetCDMIObjectOptions();

+         return (GetCDMIObjectOptions) options.metadata();

+      }

 

-		public static GetCDMIObjectOptions metadata(String prefix) {

-			GetCDMIObjectOptions options = new GetCDMIObjectOptions();

-			return (GetCDMIObjectOptions) options.metadata(prefix);

-		}

+      public static GetCDMIObjectOptions metadata(String prefix) {

+         GetCDMIObjectOptions options = new GetCDMIObjectOptions();

+         return (GetCDMIObjectOptions) options.metadata(prefix);

+      }

 

-	}

+   }

 }

diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/GetContainerOptions.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/GetContainerOptions.java
index 105ffc1..ab96e67 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/GetContainerOptions.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/options/GetContainerOptions.java
@@ -1,6 +1,5 @@
 package org.jclouds.snia.cdmi.v1.options;

 

-

 /**

  * Optional get CDMI container operations

  * 

@@ -8,89 +7,89 @@
  */

 public class GetContainerOptions extends GetCDMIObjectOptions {

 

-	public GetContainerOptions() {

-		super();

-	}

+   public GetContainerOptions() {

+      super();

+   }

 

-	/**

-	 * Get CDMI container's field

-	 * 

-	 * @param fieldname

-	 * @return this

-	 */

-	public GetContainerOptions field(String fieldname) {

-		super.field(fieldname);

-		return this;

-	}

+   /**

+    * Get CDMI container's field

+    * 

+    * @param fieldname

+    * @return this

+    */

+   public GetContainerOptions field(String fieldname) {

+      super.field(fieldname);

+      return this;

+   }

 

-	/**

-	 * Get CDMI container's metadata

-	 * 

-	 * @return this

-	 */

-	public GetContainerOptions metadata() {

-		super.metadata();

-		return this;

-	}

+   /**

+    * Get CDMI container's metadata

+    * 

+    * @return this

+    */

+   public GetContainerOptions metadata() {

+      super.metadata();

+      return this;

+   }

 

-	/**

-	 * Get CDMI container's metadata

-	 * 

-	 * @param prefix

-	 * @return this

-	 */

-	public GetContainerOptions metadata(String prefix) {

-		super.metadata(prefix);

-		return this;

-	}

+   /**

+    * Get CDMI container's metadata

+    * 

+    * @param prefix

+    * @return this

+    */

+   public GetContainerOptions metadata(String prefix) {

+      super.metadata(prefix);

+      return this;

+   }

 

-	/**

-	 * Get CDMI container's children

-	 * 

-	 * @return this

-	 */

-	public GetContainerOptions children() {

-		this.pathSuffix = this.pathSuffix + "children;";

-		return this;

-	}

+   /**

+    * Get CDMI container's children

+    * 

+    * @return this

+    */

+   public GetContainerOptions children() {

+      this.pathSuffix = this.pathSuffix + "children;";

+      return this;

+   }

 

-	/**

-	 * Get CDMI container's children in range

-	 * 

-	 * @param from

-	 * @param to

-	 * @return this

-	 */

-	public GetContainerOptions children(int from, int to) {

-		this.pathSuffix = this.pathSuffix + "children:" + from + "-" + to + ";";

-		return this;

-	}

+   /**

+    * Get CDMI container's children in range

+    * 

+    * @param from

+    * @param to

+    * @return this

+    */

+   public GetContainerOptions children(int from, int to) {

+      this.pathSuffix = this.pathSuffix + "children:" + from + "-" + to + ";";

+      return this;

+   }

 

-	public static class Builder {

-		public static GetContainerOptions field(String fieldname) {

-			GetContainerOptions options = new GetContainerOptions();

-			return (GetContainerOptions) options.field(fieldname);

-		}

+   public static class Builder {

+      public static GetContainerOptions field(String fieldname) {

+         GetContainerOptions options = new GetContainerOptions();

+         return (GetContainerOptions) options.field(fieldname);

+      }

 

-		public static GetContainerOptions metadata() {

-			GetContainerOptions options = new GetContainerOptions();

-			return (GetContainerOptions) options.metadata();

-		}

+      public static GetContainerOptions metadata() {

+         GetContainerOptions options = new GetContainerOptions();

+         return (GetContainerOptions) options.metadata();

+      }

 

-		public static GetContainerOptions metadata(String prefix) {

-			GetContainerOptions options = new GetContainerOptions();

-			return (GetContainerOptions) options.metadata(prefix);

-		}

+      public static GetContainerOptions metadata(String prefix) {

+         GetContainerOptions options = new GetContainerOptions();

+         return (GetContainerOptions) options.metadata(prefix);

+      }

 

-		public static GetContainerOptions children() {

-			GetContainerOptions options = new GetContainerOptions();

-			return (GetContainerOptions) options.children();

-		}

+      public static GetContainerOptions children() {

+         GetContainerOptions options = new GetContainerOptions();

+         return (GetContainerOptions) options.children();

+      }

 

-		public static GetContainerOptions children(int from, int to) {

-			GetContainerOptions options = new GetContainerOptions();

-			return (GetContainerOptions) options.children(from, to);

-		}

+      public static GetContainerOptions children(int from, int to) {

+         GetContainerOptions options = new GetContainerOptions();

+         return (GetContainerOptions) options.children(from, to);

+      }

 

-	}

+   }

 }

diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/CDMIObjectQueryParams.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/CDMIObjectQueryParams.java
index c55bc59..cfd9f9b 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/CDMIObjectQueryParams.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/CDMIObjectQueryParams.java
@@ -1,80 +1,68 @@
 package org.jclouds.snia.cdmi.v1.queryparams;

 

-

-

-import java.util.HashMap;

-

-import org.jclouds.http.options.BaseHttpRequestOptions;

-

-import com.google.common.collect.Multimap;

-

 /**

- * Generate CDMI object query parameters 

- * Note:  The preferred implementation would use jax-rs queryParam.

- * However, the CDMI query parameters specification does not conform to 

- * jax-rs queryParam of key=value separated by &.

- * Rather it follows the form:

- * ?<fieldname>;<fieldname>;.... 

- * ?metadata:<prefix>;...

- * ?children:<from>-<to>;...

- * ?value:<from>-<to>;...

+ * Generate CDMI object query parameters Note: The preferred implementation would use jax-rs

+ * queryParam. However, the CDMI query parameters specification does not conform to jax-rs

+ * queryParam of key=value separated by &. Rather it follows the form: ?<fieldname>;<fieldname>;....

+ * ?metadata:<prefix>;... ?children:<from>-<to>;... ?value:<from>-<to>;...

  * 

  * @author Kenneth Nagin

  */

-public class CDMIObjectQueryParams  {	

-	

-	protected String queryParams = "";

-	

-	public CDMIObjectQueryParams() {

-		super();

-	}

+public class CDMIObjectQueryParams {

 

-	/**

-	 * Get CDMI data object's field value

-	 * @param fieldname

-	 * @return this

-	 */

-	public CDMIObjectQueryParams field(String fieldname) {

-		queryParams = queryParams + fieldname + ";";

-		return this;	

-	}

-	

-	/**

-	 * Get CDMI data object's metadata

-	 * @return this

-	 */

-	public CDMIObjectQueryParams metadata() {

-		queryParams = queryParams + "metadata;";

-		return this;

-	}

+   protected String queryParams = "";

 

-	/**

-	 * Get CDMI data object's metadata associated with prefix

-	 * @param prefix

-	 * @return this

-	 */

-	public CDMIObjectQueryParams metadata(String prefix) {

-		queryParams = queryParams + "metadata:"+prefix+";";

-		return this;

-	}

-	

+   public CDMIObjectQueryParams() {

+      super();

+   }

 

-	public static class Builder {

-		public static CDMIObjectQueryParams field(

-				String fieldname) {

-			CDMIObjectQueryParams options = new CDMIObjectQueryParams();

-			return (CDMIObjectQueryParams) options.field(fieldname);

-		}

-		public static CDMIObjectQueryParams metadata(

-				String prefix) {

-			CDMIObjectQueryParams options = new CDMIObjectQueryParams();

-			return (CDMIObjectQueryParams) options.metadata(prefix);

-		}

+   /**

+    * Get CDMI data object's field value

+    * 

+    * @param fieldname

+    * @return this

+    */

+   public CDMIObjectQueryParams field(String fieldname) {

+      queryParams = queryParams + fieldname + ";";

+      return this;

+   }

 

-	}

-	

-	public String toString () {

-		return queryParams;

-	}

-	

+   /**

+    * Get CDMI data object's metadata

+    * 

+    * @return this

+    */

+   public CDMIObjectQueryParams metadata() {

+      queryParams = queryParams + "metadata;";

+      return this;

+   }

+

+   /**

+    * Get CDMI data object's metadata associated with prefix

+    * 

+    * @param prefix

+    * @return this

+    */

+   public CDMIObjectQueryParams metadata(String prefix) {

+      queryParams = queryParams + "metadata:" + prefix + ";";

+      return this;

+   }

+

+   public static class Builder {

+      public static CDMIObjectQueryParams field(String fieldname) {

+         CDMIObjectQueryParams options = new CDMIObjectQueryParams();

+         return (CDMIObjectQueryParams) options.field(fieldname);

+      }

+

+      public static CDMIObjectQueryParams metadata(String prefix) {

+         CDMIObjectQueryParams options = new CDMIObjectQueryParams();

+         return (CDMIObjectQueryParams) options.metadata(prefix);

+      }

+

+   }

+

+   public String toString() {

+      return queryParams;

+   }

+

 }

diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/ContainerQueryParams.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/ContainerQueryParams.java
index 0501940..fe7a1f0 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/ContainerQueryParams.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/ContainerQueryParams.java
@@ -1,96 +1,98 @@
 package org.jclouds.snia.cdmi.v1.queryparams;

 

 /**

- * Generate CDMI container query parameters 

- * Example:

- *   container = containerApi.getContainer(containerName,ContainerQueryParams.Builder.field("parentURI"));

- *   container = containerApi.getContainer(containerName,ContainerQueryParams.Builder.children(0,3));

+ * Generate CDMI container query parameters Example: container =

+ * containerApi.get(containerName,ContainerQueryParams.Builder.field("parentURI")); container =

+ * containerApi.get(containerName,ContainerQueryParams.Builder.children(0,3));

  * 

  * @author Kenneth Nagin

  */

-public class ContainerQueryParams extends CDMIObjectQueryParams {	

+public class ContainerQueryParams extends CDMIObjectQueryParams {

 

-	public ContainerQueryParams() {

-		super();

-	}

+   public ContainerQueryParams() {

+      super();

+   }

 

-	/**

-	 * Get CDMI container's field value

-	 * @param fieldname

-	 * @return this

-	 */

-	public ContainerQueryParams field(String fieldname) {

-		super.field(fieldname);

-		return this;	

-	}

-	

-	/**

-	 * Get CDMI container's metadata

-	 * @return this

-	 */

-	public ContainerQueryParams metadata() {

-		super.metadata();

-		return this;

-	}

+   /**

+    * Get CDMI container's field value

+    * 

+    * @param fieldname

+    * @return this

+    */

+   public ContainerQueryParams field(String fieldname) {

+      super.field(fieldname);

+      return this;

+   }

 

-	/**

-	 * Get CDMI container's metadata associated with prefix

-	 * @param prefix

-	 * @return this

-	 */

-	public ContainerQueryParams metadata(String prefix) {

-		super.metadata(prefix);

-		return this;

-	}

-	

-	/**

-	 * Get CDMI container's children

-	 * @return this

-	 */

-	public ContainerQueryParams children() {

-		queryParams = queryParams + "children;";

-		return this;

-	}

-	

-	

-	/**

-	 * Get CDMI container's children within range

-	 * @param from

-	 * @param to

-	 * @return this

-	 */

-	public ContainerQueryParams children(int from, int to) {

-		queryParams = queryParams + "children:"+from+"-"+to+";";

-		return this;

-	}

+   /**

+    * Get CDMI container's metadata

+    * 

+    * @return this

+    */

+   public ContainerQueryParams metadata() {

+      super.metadata();

+      return this;

+   }

 

+   /**

+    * Get CDMI container's metadata associated with prefix

+    * 

+    * @param prefix

+    * @return this

+    */

+   public ContainerQueryParams metadata(String prefix) {

+      super.metadata(prefix);

+      return this;

+   }

 

-	public static class Builder {

-		public static ContainerQueryParams field(

-				String fieldname) {

-			ContainerQueryParams options = new ContainerQueryParams();

-			return (ContainerQueryParams) options.field(fieldname);

-		}

-		public static ContainerQueryParams metadata() {

-			ContainerQueryParams options = new ContainerQueryParams();

-			return (ContainerQueryParams) options.metadata();

-		}

-		

-		public static ContainerQueryParams metadata(

-				String prefix) {

-			ContainerQueryParams options = new ContainerQueryParams();

-			return (ContainerQueryParams) options.metadata(prefix);

-		}

-		public static ContainerQueryParams children() {

-			ContainerQueryParams options = new ContainerQueryParams();

-			return (ContainerQueryParams) options.children();

-		}

-		public static ContainerQueryParams children(

-					int from, int to) {

-				ContainerQueryParams options = new ContainerQueryParams();

-				return (ContainerQueryParams) options.children(from,to);

-		}

+   /**

+    * Get CDMI container's children

+    * 

+    * @return this

+    */

+   public ContainerQueryParams children() {

+      queryParams = queryParams + "children;";

+      return this;

+   }

 

-	}

-	

+   /**

+    * Get CDMI container's children within range

+    * 

+    * @param from

+    * @param to

+    * @return this

+    */

+   public ContainerQueryParams children(int from, int to) {

+      queryParams = queryParams + "children:" + from + "-" + to + ";";

+      return this;

+   }

+

+   public static class Builder {

+      public static ContainerQueryParams field(String fieldname) {

+         ContainerQueryParams options = new ContainerQueryParams();

+         return (ContainerQueryParams) options.field(fieldname);

+      }

+

+      public static ContainerQueryParams metadata() {

+         ContainerQueryParams options = new ContainerQueryParams();

+         return (ContainerQueryParams) options.metadata();

+      }

+

+      public static ContainerQueryParams metadata(String prefix) {

+         ContainerQueryParams options = new ContainerQueryParams();

+         return (ContainerQueryParams) options.metadata(prefix);

+      }

+

+      public static ContainerQueryParams children() {

+         ContainerQueryParams options = new ContainerQueryParams();

+         return (ContainerQueryParams) options.children();

+      }

+

+      public static ContainerQueryParams children(int from, int to) {

+         ContainerQueryParams options = new ContainerQueryParams();

+         return (ContainerQueryParams) options.children(from, to);

+      }

+

+   }

+

 }

diff --git a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/DataObjectQueryParams.java b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/DataObjectQueryParams.java
index e70107f..f7e8fa1 100644
--- a/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/DataObjectQueryParams.java
+++ b/labs/cdmi/src/main/java/org/jclouds/snia/cdmi/v1/queryparams/DataObjectQueryParams.java
@@ -1,103 +1,98 @@
 package org.jclouds.snia.cdmi.v1.queryparams;

 

-

-

-import java.util.HashMap;

-

-import org.jclouds.http.options.BaseHttpRequestOptions;

-

-import com.google.common.collect.Multimap;

-

 /**

- * Generate CDMI data object query parameters 

- * Example:

- *   dataObject = dataApi.getDataObject(containerName,dataObjectNameIn,DataObjectQueryParams.Builder.field("parentURI"));

- *   dataObject = dataApi.getDataObject(containerName,dataObjectNameIn,DataObjectQueryParams.Builder.value());

+ * Generate CDMI data object query parameters Example: dataObject =

+ * dataApi.get(containerName,dataObjectNameIn,DataObjectQueryParams.Builder.field("parentURI"));

+ * dataObject = dataApi.get(containerName,dataObjectNameIn,DataObjectQueryParams.Builder.value());

  * 

  * @author Kenneth Nagin

  */

-public class DataObjectQueryParams extends CDMIObjectQueryParams {	

+public class DataObjectQueryParams extends CDMIObjectQueryParams {

 

-	public DataObjectQueryParams() {

-		super();

-	}

+   public DataObjectQueryParams() {

+      super();

+   }

 

-	/**

-	 * Get CDMI data object's field value

-	 * @param fieldname

-	 * @return this

-	 */

-	public DataObjectQueryParams field(String fieldname) {

-		super.field(fieldname);

-		return this;	

-	}

-	

-	/**

-	 * Get CDMI data object's metadata

-	 * @return this

-	 */

-	public DataObjectQueryParams metadata() {

-		super.metadata();

-		return this;

-	}

+   /**

+    * Get CDMI data object's field value

+    * 

+    * @param fieldname

+    * @return this

+    */

+   public DataObjectQueryParams field(String fieldname) {

+      super.field(fieldname);

+      return this;

+   }

 

-	/**

-	 * Get CDMI data object's metadata associated with prefix

-	 * @param prefix

-	 * @return this

-	 */

-	public DataObjectQueryParams metadata(String prefix) {

-		super.metadata(prefix);

-		return this;

-	}

-	

-	/**

-	 * Get CDMI data object's value with range

-	 * @return this

-	 */

-	public DataObjectQueryParams value() {

-		queryParams = queryParams + "value;";

-		return this;

-	}

-	

-	

-	/**

-	 * Get CDMI data object's value within range

-	 * @param from

-	 * @param to

-	 * @return this

-	 */

-	public DataObjectQueryParams value(int from, int to) {

-		queryParams = queryParams + "value:"+from+"-"+to+";";

-		return this;

-	}

+   /**

+    * Get CDMI data object's metadata

+    * 

+    * @return this

+    */

+   public DataObjectQueryParams metadata() {

+      super.metadata();

+      return this;

+   }

 

+   /**

+    * Get CDMI data object's metadata associated with prefix

+    * 

+    * @param prefix

+    * @return this

+    */

+   public DataObjectQueryParams metadata(String prefix) {

+      super.metadata(prefix);

+      return this;

+   }

 

-	public static class Builder {

-		public static DataObjectQueryParams field(

-				String fieldname) {

-			DataObjectQueryParams options = new DataObjectQueryParams();

-			return (DataObjectQueryParams) options.field(fieldname);

-		}

-		public static DataObjectQueryParams metadata() {

-			DataObjectQueryParams options = new DataObjectQueryParams();

-			return (DataObjectQueryParams) options.metadata();

-		}

-		public static DataObjectQueryParams metadata(

-				String prefix) {

-			DataObjectQueryParams options = new DataObjectQueryParams();

-			return (DataObjectQueryParams) options.metadata(prefix);

-		}

-		public static DataObjectQueryParams value() {

-			DataObjectQueryParams options = new DataObjectQueryParams();

-			return (DataObjectQueryParams) options.value();

-		}

-		public static DataObjectQueryParams value(

-					int from, int to) {

-				DataObjectQueryParams options = new DataObjectQueryParams();

-				return (DataObjectQueryParams) options.value(from,to);

-		}

+   /**

+    * Get CDMI data object's value with range

+    * 

+    * @return this

+    */

+   public DataObjectQueryParams value() {

+      queryParams = queryParams + "value;";

+      return this;

+   }

 

-	}

-	

+   /**

+    * Get CDMI data object's value within range

+    * 

+    * @param from

+    * @param to

+    * @return this

+    */

+   public DataObjectQueryParams value(int from, int to) {

+      queryParams = queryParams + "value:" + from + "-" + to + ";";

+      return this;

+   }

+

+   public static class Builder {

+      public static DataObjectQueryParams field(String fieldname) {

+         DataObjectQueryParams options = new DataObjectQueryParams();

+         return (DataObjectQueryParams) options.field(fieldname);

+      }

+

+      public static DataObjectQueryParams metadata() {

+         DataObjectQueryParams options = new DataObjectQueryParams();

+         return (DataObjectQueryParams) options.metadata();

+      }

+

+      public static DataObjectQueryParams metadata(String prefix) {

+         DataObjectQueryParams options = new DataObjectQueryParams();

+         return (DataObjectQueryParams) options.metadata(prefix);

+      }

+

+      public static DataObjectQueryParams value() {

+         DataObjectQueryParams options = new DataObjectQueryParams();

+         return (DataObjectQueryParams) options.value();

+      }

+

+      public static DataObjectQueryParams value(int from, int to) {

+         DataObjectQueryParams options = new DataObjectQueryParams();

+         return (DataObjectQueryParams) options.value(from, to);

+      }

+

+   }

+

 }

diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/CDMIErrorHandlerTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/CDMIErrorHandlerTest.java
index 1e470d6..6f8acbc 100644
--- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/CDMIErrorHandlerTest.java
+++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/CDMIErrorHandlerTest.java
@@ -44,29 +44,30 @@
 
    @Test
    public void test404SetsKeyNotFoundExceptionMosso() {
-      assertCodeMakes("HEAD", URI
-               .create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"), 404,
-               "Not Found", "", KeyNotFoundException.class);
+      assertCodeMakes("HEAD",
+               URI.create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"),
+               404, "Not Found", "", KeyNotFoundException.class);
    }
 
    @Test
    public void test404SetsKeyNotFoundExceptionCDMI() {
-      assertCodeMakes("HEAD", URI
-               .create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"),
+      assertCodeMakes(
+               "HEAD",
+               URI.create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1/key"),
                404, "Not Found", "", KeyNotFoundException.class);
    }
 
    @Test
    public void test404SetsContainerNotFoundExceptionMosso() {
-      assertCodeMakes("HEAD", URI
-               .create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"), 404,
+      assertCodeMakes("HEAD",
+               URI.create("http://host/v1/MossoCloudFS_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"), 404,
                "Not Found", "", ContainerNotFoundException.class);
    }
 
    @Test
    public void test404SetsContainerNotFoundExceptionCDMI() {
-      assertCodeMakes("HEAD", URI
-               .create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"),
+      assertCodeMakes("HEAD",
+               URI.create("http://67.202.39.175:8080/v1/AUTH_7064cdb1d49d4dcba3c899ac33e8409d/adriancole-blobstore1"),
                404, "Not Found", "", ContainerNotFoundException.class);
    }
 
diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerApiExpectTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerApiExpectTest.java
index 82a23c9..7205742 100644
--- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerApiExpectTest.java
+++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerApiExpectTest.java
@@ -36,30 +36,24 @@
  */
 @Test(groups = "unit", testName = "ContainerAsyncApiTest")
 public class ContainerApiExpectTest extends BaseCDMIApiExpectTest {
-   
+
    public void testGetContainerWhenResponseIs2xx() throws Exception {
 
-      HttpRequest getContainer = HttpRequest.builder()
-            .method("GET")
-            .endpoint("http://localhost:8080/MyContainer/")
-            .headers(ImmutableMultimap.<String, String> builder()
-                        .put("X-CDMI-Specification-Version", "1.0.1")
+      HttpRequest get = HttpRequest
+               .builder()
+               .method("GET")
+               .endpoint("http://localhost:8080/MyContainer/")
+               .headers(ImmutableMultimap.<String, String> builder().put("X-CDMI-Specification-Version", "1.0.1")
                         .put("TID", "tenantId")
                         .put("Authorization", "Basic " + CryptoStreams.base64("username:password".getBytes()))
-                        .put("Accept", "application/cdmi-container")
-                        .build())
-            .build();
-      
-      HttpResponse getContainerResponse = HttpResponse.builder()
-            .statusCode(200)
-            .payload(payloadFromResource("/container.json"))
-            .build();
+                        .put("Accept", "application/cdmi-container").build()).build();
 
-      CDMIApi apiWhenContainersExist = requestSendsResponse(getContainer, getContainerResponse);
+      HttpResponse getResponse = HttpResponse.builder().statusCode(200).payload(payloadFromResource("/container.json"))
+               .build();
 
-      assertEquals(
-            apiWhenContainersExist.getContainerApi().getContainer("MyContainer/"),
-            new ParseContainerTest().expected());
+      CDMIApi apiWhenContainersExist = requestSendsResponse(get, getResponse);
+
+      assertEquals(apiWhenContainersExist.getApi().get("MyContainer/"), new ParseContainerTest().expected());
    }
-   
+
 }
diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerApiLiveTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerApiLiveTest.java
index 53bfe15..7ad4537 100644
--- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerApiLiveTest.java
+++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/ContainerApiLiveTest.java
@@ -43,247 +43,224 @@
 @Test(groups = "live", testName = "ContainerApiLiveTest")
 public class ContainerApiLiveTest extends BaseCDMIApiLiveTest {
 
-	@Test
-	public void testCreateContainer() throws Exception {
-		String pContainerName = "MyContainer" + System.currentTimeMillis() + "/";
-		Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
-		Iterator<String> keys;
-		pContainerMetaDataIn.put("containerkey1", "value1");
-		pContainerMetaDataIn.put("containerkey2", "value2");
-		pContainerMetaDataIn.put("containerkey3", "value3");
+   @Test
+   public void testCreateContainer() throws Exception {
+      String pContainerName = "MyContainer" + System.currentTimeMillis() + "/";
+      Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
+      Iterator<String> keys;
+      pContainerMetaDataIn.put("containerkey1", "value1");
+      pContainerMetaDataIn.put("containerkey2", "value2");
+      pContainerMetaDataIn.put("containerkey3", "value3");
 
-		CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder
-				.metadata(pContainerMetaDataIn);
-		ContainerApi api = cdmiContext.getApi().getContainerApi();
+      CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder.metadata(pContainerMetaDataIn);
+      ContainerApi api = cdmiContext.getApi().getApi();
 
-		Logger.getAnonymousLogger().info("createContainer: " + pContainerName);
+      Logger.getAnonymousLogger().info("create: " + pContainerName);
 
-		Container container = api.createContainer(pContainerName,
-				pCreateContainerOptions);
-		assertNotNull(container);
-		try {
-			System.out.println(container);
-			Logger.getAnonymousLogger().info("getContainer: " + pContainerName);
-			container = api.getContainer(pContainerName);
-			assertNotNull(container);
-			System.out.println(container);
-			assertEquals(container.getObjectType(), ObjectTypes.CONTAINER);
-			assertNotNull(container.getObjectID());
-			assertNotNull(container.getObjectName());
-			assertEquals(container.getObjectName(), pContainerName);
-			assertEquals(container.getParentURI(), "/");
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().isEmpty(), true);
-			System.out.println("Children: " + container.getChildren());
-			assertNotNull(container.getMetadata());
-			System.out.println("Raw metadata: " + container.getMetadata());
-			keys = container.getMetadata().keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				JsonBall value = container.getMetadata().get(key);
-				System.out.println(key + ":" + value);
-			}
-			assertNotNull(container.getUserMetadata());
-			Map<String, String> pContainerMetaDataOut = container
-					.getUserMetadata();
-			keys = pContainerMetaDataIn.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				assertEquals(pContainerMetaDataOut.containsKey(key), true);
-				assertEquals(pContainerMetaDataOut.get(key),
-						pContainerMetaDataIn.get(key));
-			}
-			System.out.println("UserMetaData: " + container.getUserMetadata());
-			assertNotNull(container.getSystemMetadata());
-			System.out.println("SystemMetaData: "
-					+ container.getSystemMetadata());
-			assertNotNull(container.getACLMetadata());
-			assertEquals(container.getACLMetadata().size(),3);
-			List<Map<String, String>> aclMetadataOut = container
-					.getACLMetadata();
-			System.out.println("ACLMetaData: ");
-			for (Map<String, String> aclMap : aclMetadataOut) {
-				System.out.println(aclMap);
-			}
-			container = api.getContainer("/");
-			System.out.println("root container: " + container);
-			assertEquals(
-					container.getChildren().contains(pContainerName),
-					true);
-			System.out.println("adding containers to container");
-			String firstParentURI = api.getContainer(pContainerName).getObjectName();
-			for(int i=0;i<10;i++) {
-//				container = api.createContainer(firstParentURI+"childcontainer"+i+"/");
-				container = api.createContainer(pContainerName+"childcontainer"+i+"/");
-				assertNotNull(container);
-				System.out.println(container);
-				assertEquals(container.getParentURI(),pContainerName);
-				assertEquals(container.getObjectName(),"childcontainer"+i+"/");
-				container = api.createContainer(container.getParentURI()+container.getObjectName()+"grandchild/");
-				assertEquals(container.getParentURI(),pContainerName+"childcontainer"+i+"/");
-				assertEquals(container.getObjectName(),"grandchild/");				
-				System.out.println(container);				
-			}
-			container = api.getContainer(pContainerName);
-			assertNotNull(container);
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().size(), 10);	
-			
-		} finally {
-			Logger.getAnonymousLogger().info(
-					"deleteContainer: " + pContainerName);
-			api.deleteContainer(pContainerName);
-			container = api.getContainer("/");
-			System.out.println("root container: " + container);
-			assertEquals(
-					container.getChildren().contains(pContainerName),
-					false);
-		}
+      Container container = api.create(pContainerName, pCreateContainerOptions);
+      assertNotNull(container);
+      try {
+         System.out.println(container);
+         Logger.getAnonymousLogger().info("get: " + pContainerName);
+         container = api.get(pContainerName);
+         assertNotNull(container);
+         System.out.println(container);
+         assertEquals(container.getObjectType(), ObjectTypes.CONTAINER);
+         assertNotNull(container.getObjectID());
+         assertNotNull(container.getObjectName());
+         assertEquals(container.getObjectName(), pContainerName);
+         assertEquals(container.getParentURI(), "/");
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().isEmpty(), true);
+         System.out.println("Children: " + container.getChildren());
+         assertNotNull(container.getMetadata());
+         System.out.println("Raw metadata: " + container.getMetadata());
+         keys = container.getMetadata().keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            JsonBall value = container.getMetadata().get(key);
+            System.out.println(key + ":" + value);
+         }
+         assertNotNull(container.getUserMetadata());
+         Map<String, String> pContainerMetaDataOut = container.getUserMetadata();
+         keys = pContainerMetaDataIn.keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            assertEquals(pContainerMetaDataOut.containsKey(key), true);
+            assertEquals(pContainerMetaDataOut.get(key), pContainerMetaDataIn.get(key));
+         }
+         System.out.println("UserMetaData: " + container.getUserMetadata());
+         assertNotNull(container.getSystemMetadata());
+         System.out.println("SystemMetaData: " + container.getSystemMetadata());
+         assertNotNull(container.getACLMetadata());
+         assertEquals(container.getACLMetadata().size(), 3);
+         List<Map<String, String>> aclMetadataOut = container.getACLMetadata();
+         System.out.println("ACLMetaData: ");
+         for (Map<String, String> aclMap : aclMetadataOut) {
+            System.out.println(aclMap);
+         }
+         container = api.get("/");
+         System.out.println("root container: " + container);
+         assertEquals(container.getChildren().contains(pContainerName), true);
+         System.out.println("adding containers to container");
+         String firstParentURI = api.get(pContainerName).getObjectName();
+         for (int i = 0; i < 10; i++) {
+            // container = api.create(firstParentURI+"childcontainer"+i+"/");
+            container = api.create(pContainerName + "childcontainer" + i + "/");
+            assertNotNull(container);
+            System.out.println(container);
+            assertEquals(container.getParentURI(), pContainerName);
+            assertEquals(container.getObjectName(), "childcontainer" + i + "/");
+            container = api.create(container.getParentURI() + container.getObjectName() + "grandchild/");
+            assertEquals(container.getParentURI(), pContainerName + "childcontainer" + i + "/");
+            assertEquals(container.getObjectName(), "grandchild/");
+            System.out.println(container);
+         }
+         container = api.get(pContainerName);
+         assertNotNull(container);
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().size(), 10);
 
-	}
-	
-	@Test
-	public void testGetContainer() throws Exception {
-		String pContainerName = "MyContainer" + System.currentTimeMillis() + "/";
-		Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
-		Iterator<String> keys;
-		pContainerMetaDataIn.put("containerkey1", "value1");
-		pContainerMetaDataIn.put("containerkey2", "value2");
-		pContainerMetaDataIn.put("containerkey3", "value3");
-		CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder
-				.metadata(pContainerMetaDataIn);
-		ContainerApi api = cdmiContext.getApi().getContainerApi();
+      } finally {
+         Logger.getAnonymousLogger().info("delete: " + pContainerName);
+         api.delete(pContainerName);
+         container = api.get("/");
+         System.out.println("root container: " + container);
+         assertEquals(container.getChildren().contains(pContainerName), false);
+      }
 
-		Logger.getAnonymousLogger().info("createContainer: " + pContainerName);
+   }
 
-		Container container = api.createContainer(pContainerName,
-				pCreateContainerOptions);
-		assertNotNull(container);
-		try {
-			System.out.println(container);
-			Logger.getAnonymousLogger().info("getContainer: " + pContainerName);
-			container = api.getContainer(pContainerName);
-			assertNotNull(container);
-			System.out.println(container);
-			assertEquals(container.getObjectType(), ObjectTypes.CONTAINER);
-			assertNotNull(container.getObjectID());
-			assertNotNull(container.getObjectName());
-			assertEquals(container.getObjectName(), pContainerName);
-			assertEquals(container.getParentURI(), "/");
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().isEmpty(), true);
-			System.out.println("Children: " + container.getChildren());
-			assertNotNull(container.getMetadata());
-			System.out.println("Raw metadata: " + container.getMetadata());
-			keys = container.getMetadata().keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				JsonBall value = container.getMetadata().get(key);
-				System.out.println(key + ":" + value);
-			}
-			assertNotNull(container.getUserMetadata());
-			Map<String, String> pContainerMetaDataOut = container
-					.getUserMetadata();
-			keys = pContainerMetaDataIn.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				assertEquals(pContainerMetaDataOut.containsKey(key), true);
-				assertEquals(pContainerMetaDataOut.get(key),
-						pContainerMetaDataIn.get(key));
-			}
-			System.out.println("UserMetaData: " + container.getUserMetadata());
-			assertNotNull(container.getSystemMetadata());
-			System.out.println("SystemMetaData: "
-					+ container.getSystemMetadata());
-			assertNotNull(container.getACLMetadata());
-			List<Map<String, String>> aclMetadataOut = container
-					.getACLMetadata();
-			System.out.println("ACLMetaData: ");
-			for (Map<String, String> aclMap : aclMetadataOut) {
-				System.out.println(aclMap);
-			}
-			container = api.getContainer("/");
-			System.out.println("root container: " + container);
-			assertEquals(
-					container.getChildren().contains(pContainerName),
-					true);
-			container = api.getContainer(pContainerName,ContainerQueryParams.Builder.field("parentURI"));
-			assertNotNull(container);
-			assertEquals(container.getParentURI(),"/");
-			System.out.println(container);
-			
-			container = api.getContainer(pContainerName,ContainerQueryParams.Builder.field("parentURI").field("objectName"));
-			assertNotNull(container);
-			assertEquals(container.getParentURI(),"/");
-			assertEquals(container.getObjectName(),pContainerName);			
+   @Test
+   public void testGetContainer() throws Exception {
+      String pContainerName = "MyContainer" + System.currentTimeMillis() + "/";
+      Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
+      Iterator<String> keys;
+      pContainerMetaDataIn.put("containerkey1", "value1");
+      pContainerMetaDataIn.put("containerkey2", "value2");
+      pContainerMetaDataIn.put("containerkey3", "value3");
+      CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder.metadata(pContainerMetaDataIn);
+      ContainerApi api = cdmiContext.getApi().getApi();
 
-			container = api.getContainer(pContainerName,ContainerQueryParams.Builder.metadata());
-			assertNotNull(container);
-			pContainerMetaDataOut = container.getUserMetadata();
-			keys = pContainerMetaDataIn.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				assertEquals(pContainerMetaDataOut.containsKey(key), true);
-				assertEquals(pContainerMetaDataOut.get(key),
-						pContainerMetaDataIn.get(key));
-			}
-			System.out.println(container);
-			
-			System.out.println("GetContainerOptions.Builder.metadata(cdmi_acl)");
-			container = api.getContainer(pContainerName,ContainerQueryParams.Builder.metadata("cdmi_acl"));
-			assertNotNull(container);
-			System.out.println(container);			
-			assertNotNull(container.getACLMetadata());
-			assertEquals(container.getACLMetadata().size(),3);
+      Logger.getAnonymousLogger().info("create: " + pContainerName);
 
-			
-			System.out.println("adding containers to container");
-			String firstParentURI = api.getContainer(pContainerName).getObjectName();
-			for(int i=0;i<10;i++) {
-				container = api.createContainer(firstParentURI+"childcontainer"+i+"/");
-				assertNotNull(container);
-				assertEquals(container.getParentURI(),pContainerName);
-				assertEquals(container.getObjectName(),"childcontainer"+i+"/");
-				container = api.createContainer(container.getParentURI()+container.getObjectName()+"grandchild/",pCreateContainerOptions);
-				assertEquals(container.getParentURI(),pContainerName+"childcontainer"+i+"/");
-				assertEquals(container.getObjectName(),"grandchild"+"/");
-				container = api.getContainer(container.getParentURI(),ContainerQueryParams.Builder.children());
-				assertEquals(container.getChildren().contains("grandchild"+"/"),true);
-			}
-			container = api.getContainer(pContainerName,ContainerQueryParams.Builder.children());
-			assertNotNull(container);
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().size(), 10);
-			container = api.getContainer(pContainerName,ContainerQueryParams.Builder.children(0,3));
-			assertNotNull(container);
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().size(), 4);
-			
-			container = api.getContainer(pContainerName,ContainerQueryParams.Builder.field("parentURI").field("objectName").children().metadata());
-			assertNotNull(container);
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().size(), 10);
-			assertEquals(container.getParentURI(),"/");
-			assertEquals(container.getObjectName(),pContainerName);	
-			assertEquals(container.getParentURI(),"/");
-			assertEquals(container.getACLMetadata().size(),3);
-			for(String childName: container.getChildren()){
-				api.deleteContainer(container.getObjectName()+ childName);				
-			}
-			assertEquals(api.getContainer(pContainerName,ContainerQueryParams.Builder.children()).getChildren().isEmpty(),true);
-			
-		} finally {
-			Logger.getAnonymousLogger().info(
-					"deleteContainer: " + pContainerName);
-			api.deleteContainer(pContainerName);
-			container = api.getContainer("/");
-			System.out.println("root container: " + container);
-			assertEquals(
-					container.getChildren().contains(pContainerName),
-					false);
-		}
+      Container container = api.create(pContainerName, pCreateContainerOptions);
+      assertNotNull(container);
+      try {
+         System.out.println(container);
+         Logger.getAnonymousLogger().info("get: " + pContainerName);
+         container = api.get(pContainerName);
+         assertNotNull(container);
+         System.out.println(container);
+         assertEquals(container.getObjectType(), ObjectTypes.CONTAINER);
+         assertNotNull(container.getObjectID());
+         assertNotNull(container.getObjectName());
+         assertEquals(container.getObjectName(), pContainerName);
+         assertEquals(container.getParentURI(), "/");
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().isEmpty(), true);
+         System.out.println("Children: " + container.getChildren());
+         assertNotNull(container.getMetadata());
+         System.out.println("Raw metadata: " + container.getMetadata());
+         keys = container.getMetadata().keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            JsonBall value = container.getMetadata().get(key);
+            System.out.println(key + ":" + value);
+         }
+         assertNotNull(container.getUserMetadata());
+         Map<String, String> pContainerMetaDataOut = container.getUserMetadata();
+         keys = pContainerMetaDataIn.keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            assertEquals(pContainerMetaDataOut.containsKey(key), true);
+            assertEquals(pContainerMetaDataOut.get(key), pContainerMetaDataIn.get(key));
+         }
+         System.out.println("UserMetaData: " + container.getUserMetadata());
+         assertNotNull(container.getSystemMetadata());
+         System.out.println("SystemMetaData: " + container.getSystemMetadata());
+         assertNotNull(container.getACLMetadata());
+         List<Map<String, String>> aclMetadataOut = container.getACLMetadata();
+         System.out.println("ACLMetaData: ");
+         for (Map<String, String> aclMap : aclMetadataOut) {
+            System.out.println(aclMap);
+         }
+         container = api.get("/");
+         System.out.println("root container: " + container);
+         assertEquals(container.getChildren().contains(pContainerName), true);
+         container = api.get(pContainerName, ContainerQueryParams.Builder.field("parentURI"));
+         assertNotNull(container);
+         assertEquals(container.getParentURI(), "/");
+         System.out.println(container);
 
-	}
+         container = api.get(pContainerName, ContainerQueryParams.Builder.field("parentURI").field("objectName"));
+         assertNotNull(container);
+         assertEquals(container.getParentURI(), "/");
+         assertEquals(container.getObjectName(), pContainerName);
 
+         container = api.get(pContainerName, ContainerQueryParams.Builder.metadata());
+         assertNotNull(container);
+         pContainerMetaDataOut = container.getUserMetadata();
+         keys = pContainerMetaDataIn.keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            assertEquals(pContainerMetaDataOut.containsKey(key), true);
+            assertEquals(pContainerMetaDataOut.get(key), pContainerMetaDataIn.get(key));
+         }
+         System.out.println(container);
+
+         System.out.println("GetContainerOptions.Builder.metadata(cdmi_acl)");
+         container = api.get(pContainerName, ContainerQueryParams.Builder.metadata("cdmi_acl"));
+         assertNotNull(container);
+         System.out.println(container);
+         assertNotNull(container.getACLMetadata());
+         assertEquals(container.getACLMetadata().size(), 3);
+
+         System.out.println("adding containers to container");
+         String firstParentURI = api.get(pContainerName).getObjectName();
+         for (int i = 0; i < 10; i++) {
+            container = api.create(firstParentURI + "childcontainer" + i + "/");
+            assertNotNull(container);
+            assertEquals(container.getParentURI(), pContainerName);
+            assertEquals(container.getObjectName(), "childcontainer" + i + "/");
+            container = api.create(container.getParentURI() + container.getObjectName() + "grandchild/",
+                     pCreateContainerOptions);
+            assertEquals(container.getParentURI(), pContainerName + "childcontainer" + i + "/");
+            assertEquals(container.getObjectName(), "grandchild" + "/");
+            container = api.get(container.getParentURI(), ContainerQueryParams.Builder.children());
+            assertEquals(container.getChildren().contains("grandchild" + "/"), true);
+         }
+         container = api.get(pContainerName, ContainerQueryParams.Builder.children());
+         assertNotNull(container);
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().size(), 10);
+         container = api.get(pContainerName, ContainerQueryParams.Builder.children(0, 3));
+         assertNotNull(container);
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().size(), 4);
+
+         container = api.get(pContainerName, ContainerQueryParams.Builder.field("parentURI").field("objectName")
+                  .children().metadata());
+         assertNotNull(container);
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().size(), 10);
+         assertEquals(container.getParentURI(), "/");
+         assertEquals(container.getObjectName(), pContainerName);
+         assertEquals(container.getParentURI(), "/");
+         assertEquals(container.getACLMetadata().size(), 3);
+         for (String childName : container.getChildren()) {
+            api.delete(container.getObjectName() + childName);
+         }
+         assertEquals(api.get(pContainerName, ContainerQueryParams.Builder.children()).getChildren().isEmpty(), true);
+
+      } finally {
+         Logger.getAnonymousLogger().info("delete: " + pContainerName);
+         api.delete(pContainerName);
+         container = api.get("/");
+         System.out.println("root container: " + container);
+         assertEquals(container.getChildren().contains(pContainerName), false);
+      }
+
+   }
 
 }
diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/DataApiLiveTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/DataApiLiveTest.java
index 91200d7..6eec612 100644
--- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/DataApiLiveTest.java
+++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/DataApiLiveTest.java
@@ -50,686 +50,553 @@
  */
 @Test(groups = "live", testName = "DataApiLiveTest")
 public class DataApiLiveTest extends BaseCDMIApiLiveTest {
-	@Test
-	public void testCreateDataObjects() throws Exception {
+   @Test
+   public void testCreateDataObjects() throws Exception {
 
-		String containerName = "MyContainer" + System.currentTimeMillis() + "/";
-		String dataObjectNameIn = "dataobject08121.txt";
-		File tmpFileIn = new File("temp.txt");
-		String value;
-		InputStream is;
-		File tmpFileOut;
-		File inFile;
-		Files.touch(tmpFileIn);
-		ByteArrayOutputStream bos = new ByteArrayOutputStream();
-		DataOutputStream out = new DataOutputStream(bos);
-		byte[] bytes;
-		
-		CreateDataObjectOptions pCreateDataObjectOptions;
-		DataObject dataObject;
-		Iterator<String> keys;
-		Map<String, String> dataObjectMetaDataOut;
-		Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
-		Map<String, String> pDataObjectMetaDataIn = new LinkedHashMap<String, String>();
-		pDataObjectMetaDataIn.put("dataObjectkey1", "value1");
-		pDataObjectMetaDataIn.put("dataObjectkey2", "value2");
-		pDataObjectMetaDataIn.put("dataObjectkey3", "value3");
+      String containerName = "MyContainer" + System.currentTimeMillis() + "/";
+      String dataObjectNameIn = "dataobject08121.txt";
+      File tmpFileIn = new File("temp.txt");
+      String value;
+      InputStream is;
+      File tmpFileOut;
+      File inFile;
+      Files.touch(tmpFileIn);
+      ByteArrayOutputStream bos = new ByteArrayOutputStream();
+      DataOutputStream out = new DataOutputStream(bos);
+      byte[] bytes;
 
-		CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder
-				.metadata(pContainerMetaDataIn);
-		ContainerApi containerApi = cdmiContext.getApi()
-				.getContainerApi();
-		DataApi dataApi = cdmiContext.getApi().getDataApi();
-		Logger.getAnonymousLogger().info("createContainer: " + containerName);
-		Container container = containerApi.createContainer(containerName,
-				pCreateContainerOptions);
-		try {
-			assertNotNull(container);
-			System.out.println(container);
-			container = containerApi.getContainer(containerName);
-			assertNotNull(container);
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().isEmpty(), true);
-			
-			// exercise create data object with value mimetype and metadata
-			value = "Hello CDMI data object with value mimetype and metadata";
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(value).mimetype("text/plain")
-					.metadata(pDataObjectMetaDataIn);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getMimetype(), "text/plain");
-			assertEquals(dataObject.getValueAsString(), value);
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			keys = pDataObjectMetaDataIn.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				assertEquals(dataObjectMetaDataOut.containsKey(key), true);
-				assertEquals(dataObjectMetaDataOut.get(key),
-						pDataObjectMetaDataIn.get(key));
-			}
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName );
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+      CreateDataObjectOptions pCreateDataObjectOptions;
+      DataObject dataObject;
+      Iterator<String> keys;
+      Map<String, String> dataObjectMetaDataOut;
+      Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
+      Map<String, String> pDataObjectMetaDataIn = new LinkedHashMap<String, String>();
+      pDataObjectMetaDataIn.put("dataObjectkey1", "value1");
+      pDataObjectMetaDataIn.put("dataObjectkey2", "value2");
+      pDataObjectMetaDataIn.put("dataObjectkey3", "value3");
 
-			// verify that options order does not matter
-			value = "Hello CDMI World3";
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.metadata(pDataObjectMetaDataIn).mimetype("text/plain")
-					.value(value);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getMimetype(), "text/plain");
-			assertEquals(dataObject.getValueAsString(), value);
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			keys = pDataObjectMetaDataIn.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				assertEquals(dataObjectMetaDataOut.containsKey(key), true);
-				assertEquals(dataObjectMetaDataOut.get(key),
-						pDataObjectMetaDataIn.get(key));
-			}
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+      CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder.metadata(pContainerMetaDataIn);
+      ContainerApi containerApi = cdmiContext.getApi().getApi();
+      DataApi dataApi = cdmiContext.getApi().getDataApiForContainer(containerName);
+      Logger.getAnonymousLogger().info("create: " + containerName);
+      Container container = containerApi.create(containerName, pCreateContainerOptions);
+      try {
+         assertNotNull(container);
+         System.out.println(container);
+         container = containerApi.get(containerName);
+         assertNotNull(container);
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().isEmpty(), true);
 
-			// exercise create data object with empty metadata
-			value = "Hello CDMI World4";
-			pDataObjectMetaDataIn.clear();
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(value).mimetype("text/plain")
-					.metadata(pDataObjectMetaDataIn);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getMimetype(), "text/plain");
-			assertEquals(dataObject.getValueAsString(), value);
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			assertEquals(dataObjectMetaDataOut.isEmpty(),true);
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with value mimetype and metadata
+         value = "Hello CDMI data object with value mimetype and metadata";
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(value).mimetype("text/plain")
+                  .metadata(pDataObjectMetaDataIn);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getMimetype(), "text/plain");
+         assertEquals(dataObject.getValueAsString(), value);
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         keys = pDataObjectMetaDataIn.keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            assertEquals(dataObjectMetaDataOut.containsKey(key), true);
+            assertEquals(dataObjectMetaDataOut.get(key), pDataObjectMetaDataIn.get(key));
+         }
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
 
-			// exercise create data object with null metadata
-			value = "Hello CDMI World5";
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(
-					value).mimetype("text/plain");
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getMimetype(), "text/plain");
-			assertEquals(dataObject.getValueAsString(), value);
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			assertEquals(true, dataObjectMetaDataOut.isEmpty());
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with only value
-			value = "Hello CDMI World6";
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(value);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			assertEquals(dataObjectMetaDataOut.isEmpty(),true);
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // verify that options order does not matter
+         value = "Hello CDMI World3";
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.metadata(pDataObjectMetaDataIn)
+                  .mimetype("text/plain").value(value);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getMimetype(), "text/plain");
+         assertEquals(dataObject.getValueAsString(), value);
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         keys = pDataObjectMetaDataIn.keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            assertEquals(dataObjectMetaDataOut.containsKey(key), true);
+            assertEquals(dataObjectMetaDataOut.get(key), pDataObjectMetaDataIn.get(key));
+         }
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with empty mimetype only
-			value = "";
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.mimetype(new String());
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			//assertEquals(dataObject.getMimetype(), "");
-			assertEquals(dataObject.getValueAsString(), "");
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			//assertEquals(dataObjectMetaDataOut.isEmpty(),true);
+         // exercise create data object with empty metadata
+         value = "Hello CDMI World4";
+         pDataObjectMetaDataIn.clear();
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(value).mimetype("text/plain")
+                  .metadata(pDataObjectMetaDataIn);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getMimetype(), "text/plain");
+         assertEquals(dataObject.getValueAsString(), value);
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         assertEquals(dataObjectMetaDataOut.isEmpty(), true);
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
+         // exercise create data object with null metadata
+         value = "Hello CDMI World5";
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(value).mimetype("text/plain");
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getMimetype(), "text/plain");
+         assertEquals(dataObject.getValueAsString(), value);
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         assertEquals(true, dataObjectMetaDataOut.isEmpty());
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with no value
-			value = "";
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value();
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), "");
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			assertEquals(dataObjectMetaDataOut.isEmpty(),true);
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with only value
+         value = "Hello CDMI World6";
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(value);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         assertEquals(dataObjectMetaDataOut.isEmpty(), true);
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with byte array
-			value = "Hello CDMI World 7";
-			out.writeUTF(value);
-			out.close();
-			bytes = bos.toByteArray();
-			// String.getBytes causes an exception CreateDataObjectOptions need to investigate byte arrays
-			//bytes = value.getBytes("UTF-8");  
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(bytes);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			assertEquals(new String(dataObject.getValueAsByteArray()), value);
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with empty mimetype only
+         value = "";
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.mimetype(new String());
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         // assertEquals(dataObject.getMimetype(), "");
+         assertEquals(dataObject.getValueAsString(), "");
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         // assertEquals(dataObjectMetaDataOut.isEmpty(),true);
 
-			// exercise create data object with an existing file
-			inFile = new File(System.getProperty("user.dir")
-					+ "/src/test/resources/container.json");
-			assertEquals(true, inFile.isFile());
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(inFile);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, inFile));
-			tmpFileOut.delete();
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")),
-					Files.toString(inFile, Charsets.UTF_8).length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         dataApi.delete(dataObjectNameIn);
 
-			// exercise create data object with a temporary file that we create
-			// on the fly
-			// with default Charset
-			value = "Hello CDMI World 10";
-			Files.write(value, tmpFileIn, Charsets.UTF_8);
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(tmpFileIn);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
-			tmpFileOut.delete();
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with no value
+         value = "";
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value();
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), "");
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         assertEquals(dataObjectMetaDataOut.isEmpty(), true);
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with a temporary file that we create
-			// on the fly
-			// specify charset UTF_8
-			Files.write(value, tmpFileIn, Charsets.UTF_8);
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(
-					tmpFileIn, Charsets.UTF_8);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
-			tmpFileOut.delete();
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with byte array
+         value = "Hello CDMI World 7";
+         out.writeUTF(value);
+         out.close();
+         bytes = bos.toByteArray();
+         // String.getBytes causes an exception CreateDataObjectOptions need to investigate byte
+         // arrays
+         // bytes = value.getBytes("UTF-8");
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(bytes);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         assertEquals(new String(dataObject.getValueAsByteArray()), value);
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with a temporary file that we create
-			// on the fly
-			// specify charset US_ASCII
-			Files.write(value, tmpFileIn, Charsets.US_ASCII);
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(
-					tmpFileIn, Charsets.US_ASCII);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
-			tmpFileOut.delete();
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with an existing file
+         inFile = new File(System.getProperty("user.dir") + "/src/test/resources/container.json");
+         assertEquals(true, inFile.isFile());
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(inFile);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, inFile));
+         tmpFileOut.delete();
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")),
+                  Files.toString(inFile, Charsets.UTF_8).length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with a temporary file with multiple
-			// lines
-			// with default Charset
-			Files.write("line1", tmpFileIn, Charsets.UTF_8);
-			Files.append("\nline2", tmpFileIn, Charsets.UTF_8);
-			Files.append("\nline3", tmpFileIn, Charsets.UTF_8);
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(tmpFileIn);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), "line1\nline2\nline3");
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
-			tmpFileOut.delete();
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")),
-					Files.toString(tmpFileIn, Charsets.UTF_8).length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with a temporary file that we create
+         // on the fly
+         // with default Charset
+         value = "Hello CDMI World 10";
+         Files.write(value, tmpFileIn, Charsets.UTF_8);
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(tmpFileIn);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
+         tmpFileOut.delete();
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with a temporary file with multiple
-			// lines
-			// with Charset UTF_8
-			Files.write("line1", tmpFileIn, Charsets.UTF_8);
-			Files.append("\nline2", tmpFileIn, Charsets.UTF_8);
-			Files.append("\nline3", tmpFileIn, Charsets.UTF_8);
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(new FileInputStream(tmpFileIn));
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), "line1\nline2\nline3");
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
-			tmpFileOut.delete();
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")),
-					Files.toString(tmpFileIn, Charsets.UTF_8).length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with a temporary file that we create
+         // on the fly
+         // specify charset UTF_8
+         Files.write(value, tmpFileIn, Charsets.UTF_8);
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(tmpFileIn, Charsets.UTF_8);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
+         tmpFileOut.delete();
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with a temporary file with multiple
-			// lines
-			// with Charset ISO_8859_1
-			Files.write("line1", tmpFileIn, Charsets.ISO_8859_1);
-			Files.append("\nline2", tmpFileIn, Charsets.ISO_8859_1);
-			Files.append("\nline3", tmpFileIn, Charsets.ISO_8859_1);
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(
-					new FileInputStream(tmpFileIn), Charsets.ISO_8859_1);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), "line1\nline2\nline3");
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
-			tmpFileOut.delete();
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")),
-					Files.toString(tmpFileIn, Charsets.ISO_8859_1).length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with a temporary file that we create
+         // on the fly
+         // specify charset US_ASCII
+         Files.write(value, tmpFileIn, Charsets.US_ASCII);
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(tmpFileIn, Charsets.US_ASCII);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
+         tmpFileOut.delete();
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with an inputstream
-			is = new ByteArrayInputStream(value.getBytes());
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(is);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			assertNotNull(dataObject.getValueAsInputSupplier());
-			assertEquals(CharStreams.toString(CharStreams.newReaderSupplier(dataObject
-					.getValueAsInputSupplier(Charsets.UTF_8),Charsets.UTF_8)), value);
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
-		} finally {
-			tmpFileIn.delete();
-			containerApi.deleteContainer(containerName);
+         // exercise create data object with a temporary file with multiple
+         // lines
+         // with default Charset
+         Files.write("line1", tmpFileIn, Charsets.UTF_8);
+         Files.append("\nline2", tmpFileIn, Charsets.UTF_8);
+         Files.append("\nline3", tmpFileIn, Charsets.UTF_8);
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(tmpFileIn);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), "line1\nline2\nline3");
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
+         tmpFileOut.delete();
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")),
+                  Files.toString(tmpFileIn, Charsets.UTF_8).length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-		}
+         // exercise create data object with a temporary file with multiple
+         // lines
+         // with Charset UTF_8
+         Files.write("line1", tmpFileIn, Charsets.UTF_8);
+         Files.append("\nline2", tmpFileIn, Charsets.UTF_8);
+         Files.append("\nline3", tmpFileIn, Charsets.UTF_8);
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(new FileInputStream(tmpFileIn));
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), "line1\nline2\nline3");
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
+         tmpFileOut.delete();
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")),
+                  Files.toString(tmpFileIn, Charsets.UTF_8).length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-	}
-	
-	@Test
-	public void testGetDataObjects() throws Exception {
+         // exercise create data object with a temporary file with multiple
+         // lines
+         // with Charset ISO_8859_1
+         Files.write("line1", tmpFileIn, Charsets.ISO_8859_1);
+         Files.append("\nline2", tmpFileIn, Charsets.ISO_8859_1);
+         Files.append("\nline3", tmpFileIn, Charsets.ISO_8859_1);
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(new FileInputStream(tmpFileIn),
+                  Charsets.ISO_8859_1);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), "line1\nline2\nline3");
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
+         tmpFileOut.delete();
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")),
+                  Files.toString(tmpFileIn, Charsets.ISO_8859_1).length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-		String containerName = "MyContainer" + System.currentTimeMillis() + "/";
-		String dataObjectNameIn = "dataobject08121.txt";
-		File tmpFileIn = new File("temp.txt");
-		String value;
-		Files.touch(tmpFileIn);
-		
-		CreateDataObjectOptions pCreateDataObjectOptions;
-		DataObject dataObject;
-		Iterator<String> keys;
-		Map<String, String> dataObjectMetaDataOut;
-		Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
-		Map<String, String> pDataObjectMetaDataIn = new LinkedHashMap<String, String>();
-		pDataObjectMetaDataIn.put("dataObjectkey1", "value1");
-		pDataObjectMetaDataIn.put("dataObjectkey2", "value2");
-		pDataObjectMetaDataIn.put("dataObjectkey3", "value3");
+         // exercise create data object with an inputstream
+         is = new ByteArrayInputStream(value.getBytes());
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(is);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         assertNotNull(dataObject.getValueAsInputSupplier());
+         assertEquals(CharStreams.toString(CharStreams.newReaderSupplier(
+                  dataObject.getValueAsInputSupplier(Charsets.UTF_8), Charsets.UTF_8)), value);
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
+      } finally {
+         tmpFileIn.delete();
+         containerApi.delete(containerName);
 
-		CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder
-				.metadata(pContainerMetaDataIn);
-		ContainerApi containerApi = cdmiContext.getApi()
-				.getContainerApi();
-		DataApi dataApi = cdmiContext.getApi().getDataApi();
-		Logger.getAnonymousLogger().info("createContainer: " + containerName);
-		Container container = containerApi.createContainer(containerName,
-				pCreateContainerOptions);
-		try {
-			assertNotNull(container);
-			System.out.println(container);
-			container = containerApi.getContainer(containerName);
-			assertNotNull(container);
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().isEmpty(), true);
-			
-			// exercise create data object with value mimetype and metadata
-			value = "Hello CDMI data object with value mimetype and metadata";
-			pCreateDataObjectOptions = CreateDataObjectOptions.Builder
-					.value(value).mimetype("text/plain")
-					.metadata(pDataObjectMetaDataIn);
-			dataObject = dataApi.createDataObject(containerName,
-					dataObjectNameIn, pCreateDataObjectOptions);
-			assertNotNull(dataObject);
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getMimetype(), "text/plain");
-			assertEquals(dataObject.getValueAsString(), value);
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			keys = pDataObjectMetaDataIn.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				assertEquals(dataObjectMetaDataOut.containsKey(key), true);
-				assertEquals(dataObjectMetaDataOut.get(key),
-						pDataObjectMetaDataIn.get(key));
-			}
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn,DataObjectQueryParams.Builder.field("parentURI"));
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			assertEquals(dataObject.getParentURI(),container.getParentURI()+container.getObjectName());
-			
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn,DataObjectQueryParams.Builder.field("parentURI").field("objectName"));
-			assertNotNull(dataObject);
-			System.out.println(dataObject);			
-			assertEquals(dataObject.getParentURI(),container.getParentURI()+container.getObjectName());
-			assertEquals(dataObject.getObjectName(),dataObjectNameIn);
+      }
 
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn,DataObjectQueryParams.Builder.field("parentURI").field("objectName").field("mimetype"));
-			assertNotNull(dataObject);
-			System.out.println(dataObject);			
-			assertEquals(dataObject.getParentURI(),container.getParentURI()+container.getObjectName());
-			assertEquals(dataObject.getObjectName(),dataObjectNameIn);
-			assertEquals(dataObject.getMimetype(),"text/plain");
+   }
 
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn,DataObjectQueryParams.Builder.field("parentURI").field("objectName").field("mimetype").metadata());
-			assertNotNull(dataObject);
-			System.out.println(dataObject);			
-			assertEquals(dataObject.getParentURI(),container.getParentURI()+container.getObjectName());
-			assertEquals(dataObject.getObjectName(),dataObjectNameIn);
-			assertEquals(dataObject.getMimetype(),"text/plain");			
-			dataObjectMetaDataOut = dataObject.getUserMetadata();
-			assertNotNull(dataObjectMetaDataOut);
-			keys = pDataObjectMetaDataIn.keySet().iterator();
-			while (keys.hasNext()) {
-				String key = keys.next();
-				assertEquals(dataObjectMetaDataOut.containsKey(key), true);
-				assertEquals(dataObjectMetaDataOut.get(key),
-						pDataObjectMetaDataIn.get(key));
-			}
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn,DataObjectQueryParams.Builder.metadata("cdmi_size"));
-			assertNotNull(dataObject);
-			System.out.println(dataObject);			
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
+   @Test
+   public void testGetDataObjects() throws Exception {
 
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn,DataObjectQueryParams.Builder.field("mimetype").value());
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println(dataObject.getValueAsString());
-			assertEquals(dataObject.getMimetype(),"text/plain");
-			assertEquals(dataObject.getValueAsString(),value);
-			
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn,DataObjectQueryParams.Builder.field("mimetype").value(0,3));
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println(dataObject.getValueAsString());
-			assertEquals(dataObject.getMimetype(),"text/plain");
-			//value is SGVsbA==. This needs investigating to determine if this
-			//is problem with CDMI server or the jcloud client or must understanding of spec
+      String containerName = "MyContainer" + System.currentTimeMillis() + "/";
+      String dataObjectNameIn = "dataobject08121.txt";
+      File tmpFileIn = new File("temp.txt");
+      String value;
+      Files.touch(tmpFileIn);
 
+      CreateDataObjectOptions pCreateDataObjectOptions;
+      DataObject dataObject;
+      Iterator<String> keys;
+      Map<String, String> dataObjectMetaDataOut;
+      Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
+      Map<String, String> pDataObjectMetaDataIn = new LinkedHashMap<String, String>();
+      pDataObjectMetaDataIn.put("dataObjectkey1", "value1");
+      pDataObjectMetaDataIn.put("dataObjectkey2", "value2");
+      pDataObjectMetaDataIn.put("dataObjectkey3", "value3");
 
-			dataApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
-		} finally {
-			tmpFileIn.delete();
-			containerApi.deleteContainer(containerName);
+      CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder.metadata(pContainerMetaDataIn);
+      ContainerApi containerApi = cdmiContext.getApi().getApi();
+      DataApi dataApi = cdmiContext.getApi().getDataApiForContainer(containerName);
+      Logger.getAnonymousLogger().info("create: " + containerName);
+      Container container = containerApi.create(containerName, pCreateContainerOptions);
+      try {
+         assertNotNull(container);
+         System.out.println(container);
+         container = containerApi.get(containerName);
+         assertNotNull(container);
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().isEmpty(), true);
 
-		}
+         // exercise create data object with value mimetype and metadata
+         value = "Hello CDMI data object with value mimetype and metadata";
+         pCreateDataObjectOptions = CreateDataObjectOptions.Builder.value(value).mimetype("text/plain")
+                  .metadata(pDataObjectMetaDataIn);
+         dataObject = dataApi.create(dataObjectNameIn, pCreateDataObjectOptions);
+         assertNotNull(dataObject);
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getMimetype(), "text/plain");
+         assertEquals(dataObject.getValueAsString(), value);
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         keys = pDataObjectMetaDataIn.keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            assertEquals(dataObjectMetaDataOut.containsKey(key), true);
+            assertEquals(dataObjectMetaDataOut.get(key), pDataObjectMetaDataIn.get(key));
+         }
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
 
-	}
+         dataObject = dataApi.get(dataObjectNameIn, DataObjectQueryParams.Builder.field("parentURI"));
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         assertEquals(dataObject.getParentURI(), container.getParentURI() + container.getObjectName());
 
+         dataObject = dataApi.get(dataObjectNameIn, DataObjectQueryParams.Builder.field("parentURI")
+                  .field("objectName"));
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         assertEquals(dataObject.getParentURI(), container.getParentURI() + container.getObjectName());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+
+         dataObject = dataApi.get(dataObjectNameIn, DataObjectQueryParams.Builder.field("parentURI")
+                  .field("objectName").field("mimetype"));
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         assertEquals(dataObject.getParentURI(), container.getParentURI() + container.getObjectName());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getMimetype(), "text/plain");
+
+         dataObject = dataApi.get(dataObjectNameIn, DataObjectQueryParams.Builder.field("parentURI")
+                  .field("objectName").field("mimetype").metadata());
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         assertEquals(dataObject.getParentURI(), container.getParentURI() + container.getObjectName());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getMimetype(), "text/plain");
+         dataObjectMetaDataOut = dataObject.getUserMetadata();
+         assertNotNull(dataObjectMetaDataOut);
+         keys = pDataObjectMetaDataIn.keySet().iterator();
+         while (keys.hasNext()) {
+            String key = keys.next();
+            assertEquals(dataObjectMetaDataOut.containsKey(key), true);
+            assertEquals(dataObjectMetaDataOut.get(key), pDataObjectMetaDataIn.get(key));
+         }
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+
+         dataObject = dataApi.get(dataObjectNameIn, DataObjectQueryParams.Builder.metadata("cdmi_size"));
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+
+         dataObject = dataApi.get(dataObjectNameIn, DataObjectQueryParams.Builder.field("mimetype").value());
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println(dataObject.getValueAsString());
+         assertEquals(dataObject.getMimetype(), "text/plain");
+         assertEquals(dataObject.getValueAsString(), value);
+
+         dataObject = dataApi.get(dataObjectNameIn, DataObjectQueryParams.Builder.field("mimetype").value(0, 3));
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println(dataObject.getValueAsString());
+         assertEquals(dataObject.getMimetype(), "text/plain");
+         // value is SGVsbA==. This needs investigating to determine if this
+         // is problem with CDMI server or the jcloud client or must understanding of spec
+
+         dataApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
+      } finally {
+         tmpFileIn.delete();
+         containerApi.delete(containerName);
+
+      }
+
+   }
 
 }
diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeApiLiveTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeApiLiveTest.java
index 649b32c..570345c 100644
--- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeApiLiveTest.java
+++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/features/DataNonCDMIContentTypeApiLiveTest.java
@@ -31,6 +31,7 @@
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.logging.Logger;
+
 import org.jclouds.io.Payload;
 import org.jclouds.io.payloads.BaseMutableContentMetadata;
 import org.jclouds.io.payloads.ByteArrayPayload;
@@ -55,367 +56,300 @@
  */
 @Test(groups = "live", testName = "DataNonCDMIContentTypeApiLiveTest")
 public class DataNonCDMIContentTypeApiLiveTest extends BaseCDMIApiLiveTest {
-	@Test
-	public void testCreateDataObjectsNonCDMI() throws Exception {
+   @Test
+   public void testCreateDataObjectsNonCDMI() throws Exception {
 
-		String containerName = "MyContainer" + System.currentTimeMillis() + "/";
-		String dataObjectNameIn = "dataobject.txt";
-		File tmpFileIn = new File("temp.txt");
-		String value;
-		InputStream is;
-		File tmpFileOut;
-		File inFile;
-		Files.touch(tmpFileIn);
-		byte[] bytes;
-		DataObject dataObject;
-		Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
-		Map<String, String> pDataObjectMetaDataIn = new LinkedHashMap<String, String>();
-		pDataObjectMetaDataIn.put("dataObjectkey1", "value1");
-		pDataObjectMetaDataIn.put("dataObjectkey2", "value2");
-		pDataObjectMetaDataIn.put("dataObjectkey3", "value3");
-		
-		Payload payloadIn;
-		Payload payloadOut;
-		FileOutputStream fos;
-		
+      String containerName = "MyContainer" + System.currentTimeMillis() + "/";
+      String dataObjectNameIn = "dataobject.txt";
+      File tmpFileIn = new File("temp.txt");
+      String value;
+      InputStream is;
+      File tmpFileOut;
+      File inFile;
+      Files.touch(tmpFileIn);
+      byte[] bytes;
+      DataObject dataObject;
+      Map<String, String> pContainerMetaDataIn = new HashMap<String, String>();
+      Map<String, String> pDataObjectMetaDataIn = new LinkedHashMap<String, String>();
+      pDataObjectMetaDataIn.put("dataObjectkey1", "value1");
+      pDataObjectMetaDataIn.put("dataObjectkey2", "value2");
+      pDataObjectMetaDataIn.put("dataObjectkey3", "value3");
 
-		CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder
-				.metadata(pContainerMetaDataIn);
-		ContainerApi containerApi = cdmiContext.getApi()
-				.getContainerApi();
-		DataApi dataApi = cdmiContext.getApi().getDataApi();
-		DataNonCDMIContentTypeApi dataNonCDMIContentTypeApi = cdmiContext.getApi().getDataNonCDMIContentTypeApi();
-		Logger.getAnonymousLogger().info("createContainer: " + containerName);
-		Container container = containerApi.createContainer(containerName,
-				pCreateContainerOptions);
-		try {
-			
-			assertNotNull(container);
-			System.out.println(container);
-			container = containerApi.getContainer(containerName);
-			assertNotNull(container);
-			assertNotNull(container.getChildren());
-			assertEquals(container.getChildren().isEmpty(), true);
-			
-			// exercise create data object with none cdmi put with payload string.
-			value = "Hello CDMI World non-cdmi String";
-			dataNonCDMIContentTypeApi.createDataObject(containerName, dataObjectNameIn,
-					value);
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn);
-			assertNotNull(payloadOut);
-			assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")),value);
-			
-			payloadIn = new StringPayload(value);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.PLAIN_TEXT_UTF_8.toString())
-					.build()));
-			dataNonCDMIContentTypeApi.createDataObject(containerName, dataObjectNameIn,
-					payloadIn);
+      Payload payloadIn;
+      Payload payloadOut;
+      FileOutputStream fos;
 
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn);
-			assertNotNull(payloadOut);
-			assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")),value);
-			
-			dataObject = dataNonCDMIContentTypeApi.getDataObject(containerName, dataObjectNameIn, 
-					DataObjectQueryParams.Builder.field("parentURI"));
-			assertNotNull(dataObject);
-			System.out.println(dataObject);			
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			dataObject = dataNonCDMIContentTypeApi.getDataObject(containerName, dataObjectNameIn, 
-					DataObjectQueryParams.Builder.metadata()
-					.field("parentURI")
-					.field("objectName")
-					.field("objectType")
-					.field("mimetype"));
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(dataObject.getMimetype(),MediaType.PLAIN_TEXT_UTF_8.toString());
-			
+      CreateContainerOptions pCreateContainerOptions = CreateContainerOptions.Builder.metadata(pContainerMetaDataIn);
+      ContainerApi containerApi = cdmiContext.getApi().getApi();
+      DataApi dataApi = cdmiContext.getApi().getDataApiForContainer(containerName);
+      DataNonCDMIContentTypeApi dataNonCDMIContentTypeApi = cdmiContext.getApi()
+               .getDataNonCDMIContentTypeApiForContainer(containerName);
+      Logger.getAnonymousLogger().info("create: " + containerName);
+      Container container = containerApi.create(containerName, pCreateContainerOptions);
+      try {
 
-			
-			dataNonCDMIContentTypeApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         assertNotNull(container);
+         System.out.println(container);
+         container = containerApi.get(containerName);
+         assertNotNull(container);
+         assertNotNull(container.getChildren());
+         assertEquals(container.getChildren().isEmpty(), true);
 
-			// exercise create data object with none cdmi put with payload byte array.
-			value = "Hello CDMI World non-cdmi byte array";
-			bytes = value.getBytes("UTF-8");
-			payloadIn = new ByteArrayPayload(bytes);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.PLAIN_TEXT_UTF_8.toString())
-					.build()));
-			dataNonCDMIContentTypeApi.createDataObject(containerName, dataObjectNameIn,
-					payloadIn);
-			System.out.println(containerApi.getContainer(containerName));
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			assertEquals(new String(dataObject.getValueAsByteArray()), value);
-			assertEquals(dataObject.getUserMetadata().isEmpty(), true);
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn);
-			assertNotNull(payloadOut);
-			assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")),value);
+         // exercise create data object with none cdmi put with payload string.
+         value = "Hello CDMI World non-cdmi String";
+         dataNonCDMIContentTypeApi.create(dataObjectNameIn, value);
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn);
+         assertNotNull(payloadOut);
+         assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")), value);
 
-			
-			
-			dataNonCDMIContentTypeApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
-			
-			
-			
+         payloadIn = new StringPayload(value);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.PLAIN_TEXT_UTF_8.toString()).build()));
+         dataNonCDMIContentTypeApi.create(dataObjectNameIn, payloadIn);
 
-			// exercise create data object with none cdmi put with payload file.
-			value = "Hello CDMI World non-cdmi File";
-			Files.write(value, tmpFileIn, Charsets.UTF_8);
-			payloadIn = new FilePayload(tmpFileIn);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.PLAIN_TEXT_UTF_8.toString())
-					.build()));
-			
-			dataNonCDMIContentTypeApi.createDataObject(containerName, dataObjectNameIn,
-					payloadIn);
-			System.out.println(containerApi.getContainer(containerName));
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
-			tmpFileOut.delete();
-			assertEquals(dataObject.getUserMetadata().isEmpty(), true);
-			System.out.println("My Metadata: "+dataObject.getUserMetadata());
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn);
-			assertNotNull(payloadOut);
-			//assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")),value);
-			//byte[] _bytes = ByteStreams.toByteArray(payloadOut.getInput());
-			tmpFileOut = new File(Files.createTempDir(),"temp.txt");
-			fos = new FileOutputStream(tmpFileOut);
-			ByteStreams.copy(payloadOut.getInput(), fos);
-			fos.flush();
-			fos.close();
-			assertEquals(Files.equal(tmpFileOut, tmpFileIn),true);
-			tmpFileOut.delete();
-			
-			dataNonCDMIContentTypeApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn);
+         assertNotNull(payloadOut);
+         assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")), value);
 
-			// exercise create data object with none cdmi put with text file payload file.
-			inFile = new File(System.getProperty("user.dir")
-					+ "/src/test/resources/container.json");
-			assertEquals(true, inFile.isFile());
-			payloadIn = new FilePayload(inFile);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.JSON_UTF_8.toString())
-					.build()));
-			
-			dataNonCDMIContentTypeApi.createDataObject(containerName, inFile.getName(),
-					payloadIn);
-			System.out.println(containerApi.getContainer(containerName));
-			dataObject = dataApi.getDataObject(containerName,
-					inFile.getName());
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			//System.out.println("value: " + dataObject.getValueAsString());
-			//assertEquals(dataObject.getValueAsString(), value);
-			tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
-			assertEquals(true, Files.equal(tmpFileOut, inFile));
-			tmpFileOut.delete();
-			assertEquals(dataObject.getUserMetadata().isEmpty(), true);
-			//System.out.println("My Metadata: "+dataObject.getUserMetadata());
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), inFile.length());
-			assertEquals(dataObject.getObjectName(), inFile.getName());
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(inFile.getName()), true);
-			dataApi.deleteDataObject(containerName, inFile.getName());
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
-			
-			// exercise create data object with none cdmi put with text file payload file.
-			//inFile = new File(System.getProperty("user.dir")
-			//		+ "/src/test/resources/Jellyfish.jpg");  // takes too long when working from home
-			inFile = new File(System.getProperty("user.dir")
-					+ "/src/test/resources/yellow-flowers.jpg");
-			assertEquals(true, inFile.isFile());
-			payloadIn = new FilePayload(inFile);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.JPEG.toString())
-					.build()));			
-			dataNonCDMIContentTypeApi.createDataObject(containerName, inFile.getName(),
-					payloadIn);
-			System.out.println(containerApi.getContainer(containerName));
-			//note dataApi.getDataObject when the data object is not a string
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, inFile.getName());
-			assertNotNull(payloadOut);
-			tmpFileOut = new File(Files.createTempDir(),"temp.jpg");
-			fos = new FileOutputStream(tmpFileOut);
-			ByteStreams.copy(payloadOut.getInput(), fos);
-			fos.flush();
-			fos.close();
-			assertEquals(Files.equal(tmpFileOut, inFile),true);
-			tmpFileOut.delete();
-			
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(inFile.getName()), true);
-			dataApi.deleteDataObject(containerName, inFile.getName());
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(inFile.getName()), false);
-			
+         dataObject = dataNonCDMIContentTypeApi.get(dataObjectNameIn, DataObjectQueryParams.Builder.field("parentURI"));
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         dataObject = dataNonCDMIContentTypeApi.get(dataObjectNameIn,
+                  DataObjectQueryParams.Builder.metadata().field("parentURI").field("objectName").field("objectType")
+                           .field("mimetype"));
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(dataObject.getMimetype(), MediaType.PLAIN_TEXT_UTF_8.toString());
 
-			// exercise create data object with none cdmi put with payload inputStream riginating from string.
-			value = "Hello CDMI World non-cdmi inputStream originating from string";
-			is = new ByteArrayInputStream(value.getBytes());
-			payloadIn = new InputStreamPayload(is);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.PLAIN_TEXT_UTF_8.toString())
-					.contentLength(new Long(value.length()))
-					.build()));
-			dataNonCDMIContentTypeApi.createDataObject(containerName, dataObjectNameIn,
-					payloadIn);
-			System.out.println(containerApi.getContainer(containerName));
-			dataObject = dataApi.getDataObject(containerName,
-					dataObjectNameIn);
-			assertNotNull(dataObject);
-			System.out.println(dataObject);
-			System.out.println("value: " + dataObject.getValueAsString());
-			assertEquals(dataObject.getValueAsString(), value);
-			assertNotNull(dataObject.getValueAsInputSupplier());
-			assertEquals(CharStreams.toString(CharStreams.newReaderSupplier(dataObject
-					.getValueAsInputSupplier(Charsets.UTF_8),Charsets.UTF_8)), value);
-			assertEquals(dataObject.getUserMetadata().isEmpty(), true);
-			System.out.println("My Metadata: "+dataObject.getUserMetadata());
-			assertEquals(
-					Integer.parseInt(dataObject.getSystemMetadata().get(
-							"cdmi_size")), value.length());
-			assertEquals(dataObject.getObjectName(), dataObjectNameIn);
-			assertEquals(dataObject.getObjectType(), "application/cdmi-object");
-			assertEquals(dataObject.getParentURI(), "/" + containerName);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), true);
-			dataNonCDMIContentTypeApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);	
+         dataNonCDMIContentTypeApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			// exercise create data object with none cdmi put with payload inputStream originating from jpeg file.			
-			inFile = new File(System.getProperty("user.dir")
-					+ "/src/test/resources/yellow-flowers.jpg");
-			assertEquals(true, inFile.isFile());
-			FileInputStream fileInputStream = new FileInputStream(inFile);
-			payloadIn = new InputStreamPayload(fileInputStream);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.JPEG.toString())
-					.contentLength(new Long(inFile.length()))					
-					.build()));			
-			dataNonCDMIContentTypeApi.createDataObject(containerName, inFile.getName(),
-					payloadIn);
-			System.out.println(containerApi.getContainer(containerName));
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, inFile.getName());
-			assertNotNull(payloadOut);
-			tmpFileOut = new File(Files.createTempDir(),"temp.jpg");
-			fos = new FileOutputStream(tmpFileOut);
-			ByteStreams.copy(payloadOut.getInput(), fos);
-			fos.flush();
-			fos.close();
-			assertEquals(Files.equal(tmpFileOut, inFile),true);
-			tmpFileOut.delete();
-			
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(inFile.getName()), true);
-			dataApi.deleteDataObject(containerName, inFile.getName());
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(inFile.getName()), false);			
+         // exercise create data object with none cdmi put with payload byte array.
+         value = "Hello CDMI World non-cdmi byte array";
+         bytes = value.getBytes("UTF-8");
+         payloadIn = new ByteArrayPayload(bytes);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.PLAIN_TEXT_UTF_8.toString()).build()));
+         dataNonCDMIContentTypeApi.create(dataObjectNameIn, payloadIn);
+         System.out.println(containerApi.get(containerName));
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         assertEquals(new String(dataObject.getValueAsByteArray()), value);
+         assertEquals(dataObject.getUserMetadata().isEmpty(), true);
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn);
+         assertNotNull(payloadOut);
+         assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")), value);
 
-			// exercise get with none cdmi get range.
-			value = "Hello CDMI World non-cdmi String";
-			payloadIn = new StringPayload(value);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.PLAIN_TEXT_UTF_8.toString())
-					.build()));
-			dataNonCDMIContentTypeApi.createDataObject(containerName, dataObjectNameIn,
-					payloadIn);
+         dataNonCDMIContentTypeApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn, "bytes=0-10");
-			assertNotNull(payloadOut);
-			assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")),value.substring(0, 11));
-			assertEquals(payloadOut.getContentMetadata().getContentLength(),new Long(11));
-			
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn, "bytes=11-20");
-			assertNotNull(payloadOut);
-			assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")),value.substring(11, 21));
-			assertEquals(payloadOut.getContentMetadata().getContentLength(),new Long(10));	
-			
-			dataNonCDMIContentTypeApi.deleteDataObject(containerName, dataObjectNameIn);
-			assertEquals(containerApi.getContainer(containerName)
-					.getChildren().contains(dataObjectNameIn), false);
+         // exercise create data object with none cdmi put with payload file.
+         value = "Hello CDMI World non-cdmi File";
+         Files.write(value, tmpFileIn, Charsets.UTF_8);
+         payloadIn = new FilePayload(tmpFileIn);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.PLAIN_TEXT_UTF_8.toString()).build()));
 
-			// exercise create data object with none cdmi partial.
-			// server does not actually support cdmi partial but
-			// trace allows me to see that request was constructed properly
-			value = "Hello CDMI World non-cdmi String";
-			payloadIn = new StringPayload(value);
-			payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata().toBuilder()
-					.contentType(MediaType.PLAIN_TEXT_UTF_8.toString())
-					.build()));
-			dataNonCDMIContentTypeApi.createDataObjectPartial(containerName, dataObjectNameIn,
-					payloadIn);
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn);
-			assertNotNull(payloadOut);
-			System.out.println("payload "+payloadOut);
-			
-			dataNonCDMIContentTypeApi.createDataObjectPartial(containerName, dataObjectNameIn,
-					payloadIn);
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn);
-			assertNotNull(payloadOut);
-			System.out.println("payload "+payloadOut);
+         dataNonCDMIContentTypeApi.create(dataObjectNameIn, payloadIn);
+         System.out.println(containerApi.get(containerName));
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, tmpFileIn));
+         tmpFileOut.delete();
+         assertEquals(dataObject.getUserMetadata().isEmpty(), true);
+         System.out.println("My Metadata: " + dataObject.getUserMetadata());
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
 
-			
-			
-			dataNonCDMIContentTypeApi.createDataObject(containerName, dataObjectNameIn,
-					payloadIn);
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn);
+         assertNotNull(payloadOut);
+         // assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(),
+         // "UTF-8")),value);
+         // byte[] _bytes = ByteStreams.toByteArray(payloadOut.getInput());
+         tmpFileOut = new File(Files.createTempDir(), "temp.txt");
+         fos = new FileOutputStream(tmpFileOut);
+         ByteStreams.copy(payloadOut.getInput(), fos);
+         fos.flush();
+         fos.close();
+         assertEquals(Files.equal(tmpFileOut, tmpFileIn), true);
+         tmpFileOut.delete();
 
+         dataNonCDMIContentTypeApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-			payloadOut = dataNonCDMIContentTypeApi.getDataObjectValue(containerName, dataObjectNameIn);
-			assertNotNull(payloadOut);
-			System.out.println("payload "+payloadOut);
-		
-	
-		} finally {
-			tmpFileIn.delete();
-			containerApi.deleteContainer(containerName);
+         // exercise create data object with none cdmi put with text file payload file.
+         inFile = new File(System.getProperty("user.dir") + "/src/test/resources/container.json");
+         assertEquals(true, inFile.isFile());
+         payloadIn = new FilePayload(inFile);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.JSON_UTF_8.toString()).build()));
 
-		}
+         dataNonCDMIContentTypeApi.create(inFile.getName(), payloadIn);
+         System.out.println(containerApi.get(containerName));
+         dataObject = dataApi.get(inFile.getName());
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         // System.out.println("value: " + dataObject.getValueAsString());
+         // assertEquals(dataObject.getValueAsString(), value);
+         tmpFileOut = dataObject.getValueAsFile(Files.createTempDir());
+         assertEquals(true, Files.equal(tmpFileOut, inFile));
+         tmpFileOut.delete();
+         assertEquals(dataObject.getUserMetadata().isEmpty(), true);
+         // System.out.println("My Metadata: "+dataObject.getUserMetadata());
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), inFile.length());
+         assertEquals(dataObject.getObjectName(), inFile.getName());
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(inFile.getName()), true);
+         dataApi.delete(inFile.getName());
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
 
-	}
+         // exercise create data object with none cdmi put with text file payload file.
+         // inFile = new File(System.getProperty("user.dir")
+         // + "/src/test/resources/Jellyfish.jpg"); // takes too long when working from home
+         inFile = new File(System.getProperty("user.dir") + "/src/test/resources/yellow-flowers.jpg");
+         assertEquals(true, inFile.isFile());
+         payloadIn = new FilePayload(inFile);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.JPEG.toString()).build()));
+         dataNonCDMIContentTypeApi.create(inFile.getName(), payloadIn);
+         System.out.println(containerApi.get(containerName));
+         // note dataApi.get when the data object is not a string
+         payloadOut = dataNonCDMIContentTypeApi.getValue(inFile.getName());
+         assertNotNull(payloadOut);
+         tmpFileOut = new File(Files.createTempDir(), "temp.jpg");
+         fos = new FileOutputStream(tmpFileOut);
+         ByteStreams.copy(payloadOut.getInput(), fos);
+         fos.flush();
+         fos.close();
+         assertEquals(Files.equal(tmpFileOut, inFile), true);
+         tmpFileOut.delete();
+
+         assertEquals(containerApi.get(containerName).getChildren().contains(inFile.getName()), true);
+         dataApi.delete(inFile.getName());
+         assertEquals(containerApi.get(containerName).getChildren().contains(inFile.getName()), false);
+
+         // exercise create data object with none cdmi put with payload inputStream riginating from
+         // string.
+         value = "Hello CDMI World non-cdmi inputStream originating from string";
+         is = new ByteArrayInputStream(value.getBytes());
+         payloadIn = new InputStreamPayload(is);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.PLAIN_TEXT_UTF_8.toString())
+                  .contentLength(new Long(value.length())).build()));
+         dataNonCDMIContentTypeApi.create(dataObjectNameIn, payloadIn);
+         System.out.println(containerApi.get(containerName));
+         dataObject = dataApi.get(dataObjectNameIn);
+         assertNotNull(dataObject);
+         System.out.println(dataObject);
+         System.out.println("value: " + dataObject.getValueAsString());
+         assertEquals(dataObject.getValueAsString(), value);
+         assertNotNull(dataObject.getValueAsInputSupplier());
+         assertEquals(CharStreams.toString(CharStreams.newReaderSupplier(
+                  dataObject.getValueAsInputSupplier(Charsets.UTF_8), Charsets.UTF_8)), value);
+         assertEquals(dataObject.getUserMetadata().isEmpty(), true);
+         System.out.println("My Metadata: " + dataObject.getUserMetadata());
+         assertEquals(Integer.parseInt(dataObject.getSystemMetadata().get("cdmi_size")), value.length());
+         assertEquals(dataObject.getObjectName(), dataObjectNameIn);
+         assertEquals(dataObject.getObjectType(), "application/cdmi-object");
+         assertEquals(dataObject.getParentURI(), "/" + containerName);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), true);
+         dataNonCDMIContentTypeApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
+
+         // exercise create data object with none cdmi put with payload inputStream originating from
+         // jpeg file.
+         inFile = new File(System.getProperty("user.dir") + "/src/test/resources/yellow-flowers.jpg");
+         assertEquals(true, inFile.isFile());
+         FileInputStream fileInputStream = new FileInputStream(inFile);
+         payloadIn = new InputStreamPayload(fileInputStream);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.JPEG.toString()).contentLength(new Long(inFile.length())).build()));
+         dataNonCDMIContentTypeApi.create(inFile.getName(), payloadIn);
+         System.out.println(containerApi.get(containerName));
+         payloadOut = dataNonCDMIContentTypeApi.getValue(inFile.getName());
+         assertNotNull(payloadOut);
+         tmpFileOut = new File(Files.createTempDir(), "temp.jpg");
+         fos = new FileOutputStream(tmpFileOut);
+         ByteStreams.copy(payloadOut.getInput(), fos);
+         fos.flush();
+         fos.close();
+         assertEquals(Files.equal(tmpFileOut, inFile), true);
+         tmpFileOut.delete();
+
+         assertEquals(containerApi.get(containerName).getChildren().contains(inFile.getName()), true);
+         dataApi.delete(inFile.getName());
+         assertEquals(containerApi.get(containerName).getChildren().contains(inFile.getName()), false);
+
+         // exercise get with none cdmi get range.
+         value = "Hello CDMI World non-cdmi String";
+         payloadIn = new StringPayload(value);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.PLAIN_TEXT_UTF_8.toString()).build()));
+         dataNonCDMIContentTypeApi.create(dataObjectNameIn, payloadIn);
+
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn, "bytes=0-10");
+         assertNotNull(payloadOut);
+         assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")),
+                  value.substring(0, 11));
+         assertEquals(payloadOut.getContentMetadata().getContentLength(), new Long(11));
+
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn, "bytes=11-20");
+         assertNotNull(payloadOut);
+         assertEquals(CharStreams.toString(new InputStreamReader(payloadOut.getInput(), "UTF-8")),
+                  value.substring(11, 21));
+         assertEquals(payloadOut.getContentMetadata().getContentLength(), new Long(10));
+
+         dataNonCDMIContentTypeApi.delete(dataObjectNameIn);
+         assertEquals(containerApi.get(containerName).getChildren().contains(dataObjectNameIn), false);
+
+         // exercise create data object with none cdmi partial.
+         // server does not actually support cdmi partial but
+         // trace allows me to see that request was constructed properly
+         value = "Hello CDMI World non-cdmi String";
+         payloadIn = new StringPayload(value);
+         payloadIn.setContentMetadata(BaseMutableContentMetadata.fromContentMetadata(payloadIn.getContentMetadata()
+                  .toBuilder().contentType(MediaType.PLAIN_TEXT_UTF_8.toString()).build()));
+         dataNonCDMIContentTypeApi.createPartial(dataObjectNameIn, payloadIn);
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn);
+         assertNotNull(payloadOut);
+         System.out.println("payload " + payloadOut);
+
+         dataNonCDMIContentTypeApi.createPartial(dataObjectNameIn, payloadIn);
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn);
+         assertNotNull(payloadOut);
+         System.out.println("payload " + payloadOut);
+
+         dataNonCDMIContentTypeApi.create(dataObjectNameIn, payloadIn);
+
+         payloadOut = dataNonCDMIContentTypeApi.getValue(dataObjectNameIn);
+         assertNotNull(payloadOut);
+         System.out.println("payload " + payloadOut);
+
+      } finally {
+         tmpFileIn.delete();
+         containerApi.delete(containerName);
+
+      }
+
+   }
 
 }
diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/internal/BaseCDMIApiLiveTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/internal/BaseCDMIApiLiveTest.java
index c7afe80..1c3e412 100644
--- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/internal/BaseCDMIApiLiveTest.java
+++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/internal/BaseCDMIApiLiveTest.java
@@ -20,9 +20,9 @@
 
 import org.jclouds.apis.BaseContextLiveTest;
 import org.jclouds.rest.RestContext;
+import org.jclouds.snia.cdmi.v1.CDMIApi;
 import org.jclouds.snia.cdmi.v1.CDMIApiMetadata;
 import org.jclouds.snia.cdmi.v1.CDMIAsyncApi;
-import org.jclouds.snia.cdmi.v1.CDMIApi;
 import org.testng.annotations.AfterGroups;
 import org.testng.annotations.BeforeGroups;
 import org.testng.annotations.Test;
diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/options/ListContainersOptionsTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/options/ListContainersOptionsTest.java
index 7753483..48aba90 100644
--- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/options/ListContainersOptionsTest.java
+++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/options/ListContainersOptionsTest.java
@@ -40,6 +40,7 @@
       assert HttpRequestOptions.class.isAssignableFrom(ListContainersOptions.class);
       assert !String.class.isAssignableFrom(ListContainersOptions.class);
    }
+
    @Test
    public void testNoOptionsQueryString() {
       HttpRequestOptions options = new ListContainersOptions();
diff --git a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/parse/ParseContainerTest.java b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/parse/ParseContainerTest.java
index bdb4f8b..af43df3 100644
--- a/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/parse/ParseContainerTest.java
+++ b/labs/cdmi/src/test/java/org/jclouds/snia/cdmi/v1/parse/ParseContainerTest.java
@@ -44,17 +44,9 @@
    @Override
    @Consumes(MediaType.APPLICATION_JSON)
    public Container expected() {
-      return Container.builder()
-                      .objectType("application/cdmi-container")
-                      .objectID("00007E7F00102E230ED82694DAA975D2")
-                      .objectName("MyContainer/")
-                      .parentURI("/")
-                      .metadata(ImmutableMap.<String, JsonBall>builder()
-                          .put("cdmi_size", new JsonBall("\"83\""))
-                          .build())
-                      .children(ImmutableSet.<String>builder()
-                          .add("MyDataObject.txt")
-                          .build())
-                      .build();
+      return Container.builder().objectType("application/cdmi-container").objectID("00007E7F00102E230ED82694DAA975D2")
+               .objectName("MyContainer/").parentURI("/")
+               .metadata(ImmutableMap.<String, JsonBall> builder().put("cdmi_size", new JsonBall("\"83\"")).build())
+               .children(ImmutableSet.<String> builder().add("MyDataObject.txt").build()).build();
    }
 }
diff --git a/labs/elb/src/main/java/org/jclouds/elb/features/LoadBalancerApi.java b/labs/elb/src/main/java/org/jclouds/elb/features/LoadBalancerApi.java
index 3c2f0d3..2f31b15 100644
--- a/labs/elb/src/main/java/org/jclouds/elb/features/LoadBalancerApi.java
+++ b/labs/elb/src/main/java/org/jclouds/elb/features/LoadBalancerApi.java
@@ -39,16 +39,16 @@
 @Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
 public interface LoadBalancerApi {
 
-   String createLoadBalancerListeningInAvailabilityZones(String name, Iterable<Listener> listeners,
+   String createListeningInAvailabilityZones(String name, Iterable<Listener> listeners,
             Iterable<String> availabilityZones);
    
-   String createLoadBalancerListeningInAvailabilityZones(String name, Listener listeners,
+   String createListeningInAvailabilityZones(String name, Listener listeners,
             Iterable<String> availabilityZones);
 
-   String createLoadBalancerListeningInSubnetAssignedToSecurityGroups(String name, String subnetId,
+   String createListeningInSubnetAssignedToSecurityGroups(String name, String subnetId,
            Iterable<String> securityGroupIds);
    
-   String createLoadBalancerListeningInSubnetsAssignedToSecurityGroups(String name, Iterable<String> subnetIds,
+   String createListeningInSubnetsAssignedToSecurityGroups(String name, Iterable<String> subnetIds,
             Iterable<String> securityGroupIds);
 
 
diff --git a/labs/elb/src/main/java/org/jclouds/elb/features/LoadBalancerAsyncApi.java b/labs/elb/src/main/java/org/jclouds/elb/features/LoadBalancerAsyncApi.java
index a388041..a88b74c 100644
--- a/labs/elb/src/main/java/org/jclouds/elb/features/LoadBalancerAsyncApi.java
+++ b/labs/elb/src/main/java/org/jclouds/elb/features/LoadBalancerAsyncApi.java
@@ -45,6 +45,8 @@
 import org.jclouds.rest.annotations.Transform;
 import org.jclouds.rest.annotations.VirtualHost;
 import org.jclouds.rest.annotations.XMLResponseParser;
+import org.jclouds.rest.functions.ReturnEmptyIterableWithMarkerOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
 
@@ -63,47 +65,47 @@
 @VirtualHost
 public interface LoadBalancerAsyncApi {
    /**
-    * @see LoadBalancerApi#createLoadBalancerListeningInAvailabilityZones()
+    * @see LoadBalancerApi#createListeningInAvailabilityZones()
     */
    @POST
    @Path("/")
    @XMLResponseParser(CreateLoadBalancerResponseHandler.class)
    @FormParams(keys = ACTION, values = "CreateLoadBalancer")
-   ListenableFuture<String> createLoadBalancerListeningInAvailabilityZones(@FormParam("LoadBalancerName") String name,
+   ListenableFuture<String> createListeningInAvailabilityZones(@FormParam("LoadBalancerName") String name,
              @BinderParam(BindListenersToFormParams.class) Listener listeners,
              @BinderParam(BindAvailabilityZonesToIndexedFormParams.class) Iterable<String> availabilityZones);
     
    /**
-    * @see LoadBalancerApi#createLoadBalancerListeningInAvailabilityZones()
+    * @see LoadBalancerApi#createListeningInAvailabilityZones()
     */
    @POST
    @Path("/")
    @XMLResponseParser(CreateLoadBalancerResponseHandler.class)
    @FormParams(keys = ACTION, values = "CreateLoadBalancer")
-   ListenableFuture<String> createLoadBalancerListeningInAvailabilityZones(@FormParam("LoadBalancerName") String name,
+   ListenableFuture<String> createListeningInAvailabilityZones(@FormParam("LoadBalancerName") String name,
             @BinderParam(BindListenersToFormParams.class) Iterable<Listener> listeners,
             @BinderParam(BindAvailabilityZonesToIndexedFormParams.class) Iterable<String> availabilityZones);
 
    /**
-    * @see LoadBalancerApi#createLoadBalancerListeningInSubnetAssignedToSecurityGroups()
+    * @see LoadBalancerApi#createListeningInSubnetAssignedToSecurityGroups()
     */
    @POST
    @Path("/")
    @XMLResponseParser(CreateLoadBalancerResponseHandler.class)
    @FormParams(keys = ACTION, values = "CreateLoadBalancer")
-   ListenableFuture<String> createLoadBalancerListeningInSubnetAssignedToSecurityGroups(
+   ListenableFuture<String> createListeningInSubnetAssignedToSecurityGroups(
             @FormParam("LoadBalancerName") String name,
             @FormParam("Subnets.member.1") String subnetId,
             @BinderParam(BindSecurityGroupsToIndexedFormParams.class) Iterable<String> securityGroupIds);
    
    /**
-    * @see LoadBalancerApi#createLoadBalancerListeningInSubnetsAssignedToSecurityGroups()
+    * @see LoadBalancerApi#createListeningInSubnetsAssignedToSecurityGroups()
     */
    @POST
    @Path("/")
    @XMLResponseParser(CreateLoadBalancerResponseHandler.class)
    @FormParams(keys = ACTION, values = "CreateLoadBalancer")
-   ListenableFuture<String> createLoadBalancerListeningInSubnetsAssignedToSecurityGroups(
+   ListenableFuture<String> createListeningInSubnetsAssignedToSecurityGroups(
             @FormParam("LoadBalancerName") String name,
             @BinderParam(BindSubnetsToIndexedFormParams.class) Iterable<String> subnetIds,
             @BinderParam(BindSecurityGroupsToIndexedFormParams.class) Iterable<String> securityGroupIds);
@@ -125,6 +127,7 @@
    @Path("/")
    @XMLResponseParser(DescribeLoadBalancersResultHandler.class)
    @Transform(LoadBalancersToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
    @FormParams(keys = "Action", values = "DescribeLoadBalancers")
    ListenableFuture<PagedIterable<LoadBalancer>> list();
 
@@ -134,6 +137,7 @@
    @POST
    @Path("/")
    @XMLResponseParser(DescribeLoadBalancersResultHandler.class)
+   @ExceptionParser(ReturnEmptyIterableWithMarkerOnNotFoundOr404.class)
    @FormParams(keys = "Action", values = "DescribeLoadBalancers")
    ListenableFuture<IterableWithMarker<LoadBalancer>> list(ListLoadBalancersOptions options);
 
diff --git a/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBLoadBalanceNodesStrategy.java b/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBLoadBalanceNodesStrategy.java
index e7f901c..be5a952 100644
--- a/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBLoadBalanceNodesStrategy.java
+++ b/labs/elb/src/main/java/org/jclouds/elb/loadbalancer/strategy/ELBLoadBalanceNodesStrategy.java
@@ -82,7 +82,7 @@
 
       logger.debug(">> creating loadBalancer(%s) in zones(%s)", name, zonesDesired);
       try {
-         String dnsName = api.getLoadBalancerApiForRegion(region).createLoadBalancerListeningInAvailabilityZones(
+         String dnsName = api.getLoadBalancerApiForRegion(region).createListeningInAvailabilityZones(
                   name,
                   ImmutableSet.of(Listener.builder().port(loadBalancerPort).instancePort(instancePort)
                            .protocol(Protocol.valueOf(protocol)).build()), zonesDesired);
diff --git a/labs/elb/src/test/java/org/jclouds/elb/features/LoadBalancerApiExpectTest.java b/labs/elb/src/test/java/org/jclouds/elb/features/LoadBalancerApiExpectTest.java
index ab4ddb4..f82a6ed 100644
--- a/labs/elb/src/test/java/org/jclouds/elb/features/LoadBalancerApiExpectTest.java
+++ b/labs/elb/src/test/java/org/jclouds/elb/features/LoadBalancerApiExpectTest.java
@@ -24,6 +24,7 @@
 
 import java.util.TimeZone;
 
+import org.jclouds.collect.IterableWithMarkers;
 import org.jclouds.elb.ELBApi;
 import org.jclouds.elb.domain.LoadBalancer;
 import org.jclouds.elb.internal.BaseELBApiExpectTest;
@@ -31,7 +32,6 @@
 import org.jclouds.elb.parse.GetLoadBalancerResponseTest;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
-import org.jclouds.rest.ResourceNotFoundException;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableSet;
@@ -197,8 +197,6 @@
       assertEquals(ImmutableSet.copyOf(Iterables.concat(apiWhenExist.getLoadBalancerApiForRegion("eu-west-1").list())), ImmutableSet.of(lb1, lb2));
    }
    
-   // TODO: this should really be an empty set
-   @Test(expectedExceptions = ResourceNotFoundException.class)
    public void testListWhenResponseIs404() throws Exception {
 
       HttpResponse listResponse = HttpResponse.builder().statusCode(404).build();
@@ -206,7 +204,8 @@
       ELBApi apiWhenDontExist = requestSendsResponse(
             list, listResponse);
 
-      apiWhenDontExist.getLoadBalancerApi().list();
+      assertEquals(apiWhenDontExist.getLoadBalancerApi().list().get(0), IterableWithMarkers.EMPTY);
+
    }
    
    public void testListWithOptionsWhenResponseIs2xx() throws Exception {
diff --git a/labs/fgcp-au/src/main/java/org/jclouds/fujitsu/fgcp/FGCPAUProviderMetadata.java b/labs/fgcp-au/src/main/java/org/jclouds/fujitsu/fgcp/FGCPAUProviderMetadata.java
index b17d6ca..b3efbe7 100644
--- a/labs/fgcp-au/src/main/java/org/jclouds/fujitsu/fgcp/FGCPAUProviderMetadata.java
+++ b/labs/fgcp-au/src/main/java/org/jclouds/fujitsu/fgcp/FGCPAUProviderMetadata.java
@@ -30,48 +30,51 @@
  */
 public class FGCPAUProviderMetadata extends FGCPProviderMetadata {
 
-    public static Builder builder() {
-        return new Builder();
-    }
+   /** The serialVersionUID */
+   private static final long serialVersionUID = 1735901960026547803L;
 
-    public FGCPAUProviderMetadata() {
-        super(builder());
-    }
+   public static Builder builder() {
+      return new Builder();
+   }
 
-    public FGCPAUProviderMetadata(Builder builder) {
-        super(builder);
-    }
+   public FGCPAUProviderMetadata() {
+      super(builder());
+   }
 
-    @Override
-    public Builder toBuilder() {
-        return builder().fromProviderMetadata(this);
-    }
+   public FGCPAUProviderMetadata(Builder builder) {
+      super(builder);
+   }
 
-    public static class Builder extends BaseProviderMetadata.Builder {
+   @Override
+   public Builder toBuilder() {
+      return builder().fromProviderMetadata(this);
+   }
 
-        protected Builder() {
-            id("fgcp-au")
-                    .name("Fujitsu Global Cloud Platform (FGCP) - AU")
-                    .apiMetadata(new FGCPApiMetadata())
-                    .homepage(
-                            URI.create("http://www.fujitsu.com/global/solutions/cloud/solutions/global-cloud-platform/index.html"))
-                    .console(URI.create("http://globalcloud.fujitsu.com.au"))
-                    .defaultProperties(FGCPApiMetadata.defaultProperties())
-                    .iso3166Codes("AU-NSW")
-                    .endpoint(
-                            "https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint")
-                    .defaultProperties(FGCPProviderMetadata.defaultProperties());
-        }
+   public static class Builder extends BaseProviderMetadata.Builder {
 
-        @Override
-        public FGCPAUProviderMetadata build() {
-            return new FGCPAUProviderMetadata(this);
-        }
+      protected Builder() {
+         id("fgcp-au")
+               .name("Fujitsu Global Cloud Platform (FGCP) - AU")
+               .apiMetadata(new FGCPApiMetadata())
+               .homepage(
+                     URI.create("http://www.fujitsu.com/global/solutions/cloud/solutions/global-cloud-platform/index.html"))
+               .console(URI.create("http://globalcloud.fujitsu.com.au"))
+               .defaultProperties(FGCPApiMetadata.defaultProperties())
+               .iso3166Codes("AU-NSW")
+               .endpoint(
+                     "https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint")
+               .defaultProperties(FGCPProviderMetadata.defaultProperties());
+      }
 
-        @Override
-        public Builder fromProviderMetadata(ProviderMetadata in) {
-            super.fromProviderMetadata(in);
-            return this;
-        }
-    }
+      @Override
+      public FGCPAUProviderMetadata build() {
+         return new FGCPAUProviderMetadata(this);
+      }
+
+      @Override
+      public Builder fromProviderMetadata(ProviderMetadata in) {
+         super.fromProviderMetadata(in);
+         return this;
+      }
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/FGCPAUProviderTest.java b/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/FGCPAUProviderTest.java
index 9a2ddbc..fa37d4d 100644
--- a/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/FGCPAUProviderTest.java
+++ b/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/FGCPAUProviderTest.java
@@ -28,7 +28,7 @@
 public class FGCPAUProviderTest extends BaseProviderMetadataTest {
 
    public FGCPAUProviderTest() {
-      super(new FGCPAUProviderMetadata(), new FGCPApiMetadata());
+     super(new FGCPAUProviderMetadata(), new FGCPApiMetadata());
    }
 
 }
diff --git a/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPAUTemplateBuilderLiveTest.java b/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPAUTemplateBuilderLiveTest.java
index 30f12de..b3881e6 100644
--- a/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPAUTemplateBuilderLiveTest.java
+++ b/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPAUTemplateBuilderLiveTest.java
@@ -30,14 +30,14 @@
  */
 @Test(groups = "live", enabled = true, singleThreaded = true, testName = "FGCPAUTemplateBuilderLiveTest")
 public class FGCPAUTemplateBuilderLiveTest extends
-        FGCPBaseTemplateBuilderLiveTest {
+      FGCPBaseTemplateBuilderLiveTest {
 
-    public FGCPAUTemplateBuilderLiveTest() {
-        provider = "fgcp-au";
-    }
+   public FGCPAUTemplateBuilderLiveTest() {
+      provider = "fgcp-au";
+   }
 
-    @Override
-    protected Set<String> getIso3166Codes() {
-        return ImmutableSet.<String> of("AU-NSW");
-    }
+   @Override
+   protected Set<String> getIso3166Codes() {
+      return ImmutableSet.<String> of("AU-NSW");
+   }
 }
diff --git a/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPAUComputeServiceLiveTest.java b/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPAUComputeServiceLiveTest.java
index 49c23ff..15f8ab1 100644
--- a/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPAUComputeServiceLiveTest.java
+++ b/labs/fgcp-au/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPAUComputeServiceLiveTest.java
@@ -29,9 +29,9 @@
 @Test(groups = "live", enabled = true, singleThreaded = true, testName = "FGCPAUComputeServiceLiveTest")
 public class FGCPAUComputeServiceLiveTest extends FGCPBaseComputeServiceLiveTest {
 
-    @Override
-    public void setServiceDefaults() {
-        provider = "fgcp-au";
-    }
+   @Override
+   public void setServiceDefaults() {
+      provider = "fgcp-au";
+   }
 
 }
diff --git a/labs/fgcp-de/src/main/java/org/jclouds/fujitsu/fgcp/FGCPDEProviderMetadata.java b/labs/fgcp-de/src/main/java/org/jclouds/fujitsu/fgcp/FGCPDEProviderMetadata.java
index db087a5..2868f35 100644
--- a/labs/fgcp-de/src/main/java/org/jclouds/fujitsu/fgcp/FGCPDEProviderMetadata.java
+++ b/labs/fgcp-de/src/main/java/org/jclouds/fujitsu/fgcp/FGCPDEProviderMetadata.java
@@ -30,50 +30,50 @@
  */
 public class FGCPDEProviderMetadata extends FGCPProviderMetadata {
 
-    private static final long serialVersionUID = -8498457904032259345L;
+   private static final long serialVersionUID = -8498457904032259345L;
 
-    public static Builder builder() {
-        return new Builder();
-    }
+   public static Builder builder() {
+      return new Builder();
+   }
 
-    public FGCPDEProviderMetadata() {
-        super(builder());
-    }
+   public FGCPDEProviderMetadata() {
+      super(builder());
+   }
 
-    public FGCPDEProviderMetadata(Builder builder) {
-        super(builder);
-    }
+   public FGCPDEProviderMetadata(Builder builder) {
+      super(builder);
+   }
 
-    @Override
-    public Builder toBuilder() {
-        return builder().fromProviderMetadata(this);
-    }
+   @Override
+   public Builder toBuilder() {
+      return builder().fromProviderMetadata(this);
+   }
 
-    public static class Builder extends BaseProviderMetadata.Builder {
+   public static class Builder extends BaseProviderMetadata.Builder {
 
-        protected Builder() {
-            id("fgcp-de")
-                    .name("Fujitsu Global Cloud Platform (FGCP) - DE")
-                    .apiMetadata(new FGCPApiMetadata())
-                    .homepage(
-                            URI.create("http://www.fujitsu.com/global/solutions/cloud/solutions/global-cloud-platform/index.html"))
-                    .console(URI.create("http://globalcloud.de.fujitsu.com"))
-                    .defaultProperties(FGCPApiMetadata.defaultProperties())
-                    .iso3166Codes("DE-BY")
-                    .endpoint(
-                            "https://api.globalcloud.de.fujitsu.com/ovissapi/endpoint")
-                    .defaultProperties(FGCPProviderMetadata.defaultProperties());
-        }
+      protected Builder() {
+         id("fgcp-de")
+               .name("Fujitsu Global Cloud Platform (FGCP) - DE")
+               .apiMetadata(new FGCPApiMetadata())
+               .homepage(
+                     URI.create("http://www.fujitsu.com/global/solutions/cloud/solutions/global-cloud-platform/index.html"))
+               .console(URI.create("http://globalcloud.de.fujitsu.com"))
+               .defaultProperties(FGCPApiMetadata.defaultProperties())
+               .iso3166Codes("DE-BY")
+               .endpoint(
+                     "https://api.globalcloud.de.fujitsu.com/ovissapi/endpoint")
+               .defaultProperties(FGCPProviderMetadata.defaultProperties());
+      }
 
-        @Override
-        public FGCPDEProviderMetadata build() {
-            return new FGCPDEProviderMetadata(this);
-        }
+      @Override
+      public FGCPDEProviderMetadata build() {
+         return new FGCPDEProviderMetadata(this);
+      }
 
-        @Override
-        public Builder fromProviderMetadata(ProviderMetadata in) {
-            super.fromProviderMetadata(in);
-            return this;
-        }
-    }
+      @Override
+      public Builder fromProviderMetadata(ProviderMetadata in) {
+         super.fromProviderMetadata(in);
+         return this;
+      }
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/FGCPDEProviderTest.java b/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/FGCPDEProviderTest.java
index 99b37d2..175cb3d 100644
--- a/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/FGCPDEProviderTest.java
+++ b/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/FGCPDEProviderTest.java
@@ -28,7 +28,7 @@
 public class FGCPDEProviderTest extends BaseProviderMetadataTest {
 
    public FGCPDEProviderTest() {
-      super(new FGCPDEProviderMetadata(), new FGCPApiMetadata());
+     super(new FGCPDEProviderMetadata(), new FGCPApiMetadata());
    }
 
 }
diff --git a/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPDETemplateBuilderLiveTest.java b/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPDETemplateBuilderLiveTest.java
index 0894978..eaf6aea 100644
--- a/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPDETemplateBuilderLiveTest.java
+++ b/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPDETemplateBuilderLiveTest.java
@@ -30,14 +30,14 @@
  */
 @Test(groups = "live", enabled = true, singleThreaded = true, testName = "FGCPDETemplateBuilderLiveTest")
 public class FGCPDETemplateBuilderLiveTest extends
-        FGCPBaseTemplateBuilderLiveTest {
+      FGCPBaseTemplateBuilderLiveTest {
 
-    public FGCPDETemplateBuilderLiveTest() {
-        provider = "fgcp-de";
-    }
+   public FGCPDETemplateBuilderLiveTest() {
+      provider = "fgcp-de";
+   }
 
-    @Override
-    protected Set<String> getIso3166Codes() {
-        return ImmutableSet.<String> of("DE-BY");
-    }
+   @Override
+   protected Set<String> getIso3166Codes() {
+      return ImmutableSet.<String> of("DE-BY");
+   }
 }
diff --git a/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPDEComputeServiceLiveTest.java b/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPDEComputeServiceLiveTest.java
index f0de559..23f1cd7 100644
--- a/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPDEComputeServiceLiveTest.java
+++ b/labs/fgcp-de/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPDEComputeServiceLiveTest.java
@@ -29,9 +29,9 @@
 @Test(groups = "live", enabled = true, singleThreaded = true, testName = "FGCPDEComputeServiceLiveTest")
 public class FGCPDEComputeServiceLiveTest extends FGCPBaseComputeServiceLiveTest {
 
-    @Override
-    public void setServiceDefaults() {
-        provider = "fgcp-de";
-    }
+   @Override
+   public void setServiceDefaults() {
+      provider = "fgcp-de";
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPApi.java
index 54561af..c2175f9 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPApi.java
@@ -40,30 +40,30 @@
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface FGCPApi {
 
-    @Delegate
-    VirtualDCApi getVirtualDCApi();
+   @Delegate
+   VirtualDCApi getVirtualDCApi();
 
-    @Delegate
-    VirtualSystemApi getVirtualSystemApi();
+   @Delegate
+   VirtualSystemApi getVirtualSystemApi();
 
-    @Delegate
-    VirtualServerApi getVirtualServerApi();
+   @Delegate
+   VirtualServerApi getVirtualServerApi();
 
-    @Delegate
-    AdditionalDiskApi getAdditionalDiskApi();
+   @Delegate
+   AdditionalDiskApi getAdditionalDiskApi();
 
-    @Delegate
-    SystemTemplateApi getSystemTemplateApi();
+   @Delegate
+   SystemTemplateApi getSystemTemplateApi();
 
-    @Delegate
-    DiskImageApi getDiskImageApi();
+   @Delegate
+   DiskImageApi getDiskImageApi();
 
-    @Delegate
-    FirewallApi getFirewallApi();
+   @Delegate
+   FirewallApi getFirewallApi();
 
-    @Delegate
-    LoadBalancerApi getLoadBalancerApi();
+   @Delegate
+   LoadBalancerApi getLoadBalancerApi();
 
-    @Delegate
-    PublicIPAddressApi getPublicIPAddressApi();
+   @Delegate
+   PublicIPAddressApi getPublicIPAddressApi();
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPApiMetadata.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPApiMetadata.java
index 0f5e9fd..c187b7e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPApiMetadata.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPApiMetadata.java
@@ -40,60 +40,63 @@
  */
 public class FGCPApiMetadata extends BaseRestApiMetadata {
 
-    @Override
-    public Builder toBuilder() {
-        return new Builder().fromApiMetadata(this);
-    }
+   /** The serialVersionUID */
+   private static final long serialVersionUID = -8430912756058292588L;
 
-    public FGCPApiMetadata() {
-        this(new Builder());
-    }
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
 
-    protected FGCPApiMetadata(Builder builder) {
-        super(builder);
-    }
+   public FGCPApiMetadata() {
+      this(new Builder());
+   }
 
-    public static Properties defaultProperties() {
-        Properties properties = BaseRestApiMetadata.defaultProperties();
-        // enables peer verification using the CAs bundled with the JRE (or
-        // value of javax.net.ssl.trustStore if set)
-        properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
-        // properties.setProperty("jclouds.ssh.max-retries", "5");
-        // properties.setProperty("jclouds.ssh.retry-auth", "true");
-        return properties;
-    }
+   protected FGCPApiMetadata(Builder builder) {
+      super(builder);
+   }
 
-    public static class Builder extends BaseRestApiMetadata.Builder {
+   public static Properties defaultProperties() {
+      Properties properties = BaseRestApiMetadata.defaultProperties();
+      // enables peer verification using the CAs bundled with the JRE (or
+      // value of javax.net.ssl.trustStore if set)
+      properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
+      // properties.setProperty("jclouds.ssh.max-retries", "5");
+      // properties.setProperty("jclouds.ssh.retry-auth", "true");
+      return properties;
+   }
 
-        protected Builder() {
-            super(FGCPApi.class, FGCPAsyncApi.class);
-            id("fgcp")
-                    .name("Fujitsu Global Cloud Platform (FGCP)")
-                    .identityName("User certificate (PEM file)")
-                    .credentialName("User certificate password")
-                    .documentation(
-                            URI.create("https://globalcloud.fujitsu.com.au/portala/ctrl/aboutSopManual"))
-                    .version(FGCPAsyncApi.VERSION)
-                    .defaultEndpoint(
-                            "https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint")
-                    .defaultProperties(FGCPApiMetadata.defaultProperties())
-                    .view(TypeToken.of(ComputeServiceContext.class))
-                    .defaultModules(
-                            ImmutableSet.<Class<? extends Module>> of(
-                                    FGCPComputeServiceContextModule.class,
-                                    FGCPRestClientModule.class));
-        }
+   public static class Builder extends BaseRestApiMetadata.Builder {
 
-        @Override
-        public FGCPApiMetadata build() {
-            return new FGCPApiMetadata(this);
-        }
+      protected Builder() {
+         super(FGCPApi.class, FGCPAsyncApi.class);
+         id("fgcp")
+               .name("Fujitsu Global Cloud Platform (FGCP)")
+               .identityName("User certificate (PEM file)")
+               .credentialName("User certificate password")
+               .documentation(
+                     URI.create("https://globalcloud.fujitsu.com.au/portala/ctrl/aboutSopManual"))
+               .version(FGCPAsyncApi.VERSION)
+               .defaultEndpoint(
+                     "https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint")
+               .defaultProperties(FGCPApiMetadata.defaultProperties())
+               .view(TypeToken.of(ComputeServiceContext.class))
+               .defaultModules(
+                     ImmutableSet.<Class<? extends Module>> of(
+                           FGCPComputeServiceContextModule.class,
+                           FGCPRestClientModule.class));
+      }
 
-        @Override
-        public Builder fromApiMetadata(ApiMetadata in) {
-            super.fromApiMetadata(in);
-            return this;
-        }
+      @Override
+      public FGCPApiMetadata build() {
+         return new FGCPApiMetadata(this);
+      }
 
-    }
+      @Override
+      public Builder fromApiMetadata(ApiMetadata in) {
+         super.fromApiMetadata(in);
+         return this;
+      }
+
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPAsyncApi.java
index 9eda1dd..5a3d5e4 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPAsyncApi.java
@@ -35,32 +35,32 @@
  * @author Dies Koper
  */
 public interface FGCPAsyncApi {
-    public final static String VERSION = "2012-02-18";
+   public final static String VERSION = "2012-02-18";
 
-    @Delegate
-    VirtualDCAsyncApi getVirtualDCApi();
+   @Delegate
+   VirtualDCAsyncApi getVirtualDCApi();
 
-    @Delegate
-    VirtualSystemAsyncApi getVirtualSystemApi();
+   @Delegate
+   VirtualSystemAsyncApi getVirtualSystemApi();
 
-    @Delegate
-    VirtualServerAsyncApi getVirtualServerApi();
+   @Delegate
+   VirtualServerAsyncApi getVirtualServerApi();
 
-    @Delegate
-    AdditionalDiskAsyncApi getAdditionalDiskApi();
+   @Delegate
+   AdditionalDiskAsyncApi getAdditionalDiskApi();
 
-    @Delegate
-    SystemTemplateAsyncApi getSystemTemplateApi();
+   @Delegate
+   SystemTemplateAsyncApi getSystemTemplateApi();
 
-    @Delegate
-    DiskImageAsyncApi getDiskImageApi();
+   @Delegate
+   DiskImageAsyncApi getDiskImageApi();
 
-    @Delegate
-    FirewallAsyncApi getFirewallApi();
+   @Delegate
+   FirewallAsyncApi getFirewallApi();
 
-    @Delegate
-    LoadBalancerAsyncApi getLoadBalancerApi();
+   @Delegate
+   LoadBalancerAsyncApi getLoadBalancerApi();
 
-    @Delegate
-    PublicIPAddressAsyncApi getPublicIPAddressApi();
+   @Delegate
+   PublicIPAddressAsyncApi getPublicIPAddressApi();
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPProviderMetadata.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPProviderMetadata.java
index a7718d4..7989cda 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPProviderMetadata.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/FGCPProviderMetadata.java
@@ -32,26 +32,26 @@
  */
 public class FGCPProviderMetadata extends BaseProviderMetadata {
 
-    private static final long serialVersionUID = 7527265705102650456L;
+   private static final long serialVersionUID = 7527265705102650456L;
 
-    public static Builder builder() {
-        return new Builder();
-    }
+   public static Builder builder() {
+      return new Builder();
+   }
 
-    public FGCPProviderMetadata() {
-        super(builder());
-    }
+   public FGCPProviderMetadata() {
+      super(builder());
+   }
 
-    public FGCPProviderMetadata(Builder builder) {
-        super(builder);
-    }
+   public FGCPProviderMetadata(Builder builder) {
+      super(builder);
+   }
 
-    public static Properties defaultProperties() {
-        Properties properties = new Properties();
+   public static Properties defaultProperties() {
+      Properties properties = new Properties();
 
-        properties.setProperty(TEMPLATE,
-                "osFamily=CENTOS,osVersionMatches=6.2,os64Bit=true");
+      properties.setProperty(TEMPLATE,
+            "osFamily=CENTOS,osVersionMatches=6.2,os64Bit=true");
 
-        return properties;
-    }
+      return properties;
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/binders/BindAlsoToSystemId.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/binders/BindAlsoToSystemId.java
index 0986997..887d52b 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/binders/BindAlsoToSystemId.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/binders/BindAlsoToSystemId.java
@@ -38,33 +38,33 @@
 @Singleton
 public class BindAlsoToSystemId implements Binder {
 
-    /**
-     * 
-     * @param request
-     *            request where the query params will be set
-     * @param input
-     *            array of String params
-     */
-    @SuppressWarnings("unchecked")
-    @Override
-    public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+   /**
+    * 
+    * @param request
+    *         request where the query params will be set
+    * @param input
+    *         array of String params
+    */
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
 
-        checkNotNull(input);
-        checkArgument(
-                input instanceof String,
-                "this binder only applies to String arguments: "
-                        + input.getClass());
+      checkNotNull(input);
+      checkArgument(
+            input instanceof String,
+            "this binder only applies to String arguments: "
+                  + input.getClass());
 
-        Pattern pattern = Pattern.compile("^(\\w+-\\w+)\\b.*");
-        Matcher matcher = pattern.matcher((String) input);
+      Pattern pattern = Pattern.compile("^(\\w+-\\w+)\\b.*");
+      Matcher matcher = pattern.matcher((String) input);
 
-        checkArgument(matcher.find(),
-                "no valid resource id found to construct vsys id from: "
-                        + input.toString());
+      checkArgument(matcher.find(),
+            "no valid resource id found to construct vsys id from: "
+                  + input.toString());
 
-        Builder<?> builder = request.toBuilder();
-        builder.replaceQueryParam("vsysId", matcher.group(1));
+      Builder<?> builder = request.toBuilder();
+      builder.replaceQueryParam("vsysId", matcher.group(1));
 
-        return (R) builder.build();
-    }
+      return (R) builder.build();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/FGCPRestClientModule.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/FGCPRestClientModule.java
index c86abea..357782a 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/FGCPRestClientModule.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/FGCPRestClientModule.java
@@ -92,284 +92,284 @@
  */
 @ConfiguresRestClient
 public class FGCPRestClientModule extends
-        RestClientModule<FGCPApi, FGCPAsyncApi> {
+      RestClientModule<FGCPApi, FGCPAsyncApi> {
 
-    @Resource
-    Logger logger = Logger.NULL;
+   @Resource
+   Logger logger = Logger.NULL;
 
-    public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap
-            .<Class<?>, Class<?>> builder()
-            //
-            .put(VirtualDCApi.class, VirtualDCAsyncApi.class)
-            .put(VirtualSystemApi.class, VirtualSystemAsyncApi.class)
-            .put(VirtualServerApi.class, VirtualServerAsyncApi.class)
-            .put(AdditionalDiskApi.class, AdditionalDiskAsyncApi.class)
-            .put(SystemTemplateApi.class, SystemTemplateAsyncApi.class)
-            .put(DiskImageApi.class, DiskImageAsyncApi.class)
-            .put(BuiltinServerApi.class, BuiltinServerAsyncApi.class)
-            .put(FirewallApi.class, FirewallAsyncApi.class)
-            .put(LoadBalancerApi.class, LoadBalancerAsyncApi.class)
-            .put(PublicIPAddressApi.class, PublicIPAddressAsyncApi.class)
-            .build();
+   public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap
+         .<Class<?>, Class<?>> builder()
+         //
+         .put(VirtualDCApi.class, VirtualDCAsyncApi.class)
+         .put(VirtualSystemApi.class, VirtualSystemAsyncApi.class)
+         .put(VirtualServerApi.class, VirtualServerAsyncApi.class)
+         .put(AdditionalDiskApi.class, AdditionalDiskAsyncApi.class)
+         .put(SystemTemplateApi.class, SystemTemplateAsyncApi.class)
+         .put(DiskImageApi.class, DiskImageAsyncApi.class)
+         .put(BuiltinServerApi.class, BuiltinServerAsyncApi.class)
+         .put(FirewallApi.class, FirewallAsyncApi.class)
+         .put(LoadBalancerApi.class, LoadBalancerAsyncApi.class)
+         .put(PublicIPAddressApi.class, PublicIPAddressAsyncApi.class)
+         .build();
 
-    public FGCPRestClientModule() {
-        super(DELEGATE_MAP);
-    }
+   public FGCPRestClientModule() {
+      super(DELEGATE_MAP);
+   }
 
-    @Override
-    protected void bindErrorHandlers() {
-        // bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseAWSErrorFromXmlContent.class);
-        // bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseAWSErrorFromXmlContent.class);
-        // bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseAWSErrorFromXmlContent.class);
-    }
+   @Override
+   protected void bindErrorHandlers() {
+      // bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseAWSErrorFromXmlContent.class);
+      // bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseAWSErrorFromXmlContent.class);
+      // bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseAWSErrorFromXmlContent.class);
+   }
 
-    @Override
-    protected void installLocations() {
-        super.installLocations();
-        bind(ImplicitLocationSupplier.class).to(FirstNetwork.class).in(
-                Scopes.SINGLETON);
-        bind(LocationsSupplier.class).to(
-                SystemAndNetworkSegmentToLocationSupplier.class).in(
-                Scopes.SINGLETON);
-    }
+   @Override
+   protected void installLocations() {
+      super.installLocations();
+      bind(ImplicitLocationSupplier.class).to(FirstNetwork.class).in(
+            Scopes.SINGLETON);
+      bind(LocationsSupplier.class).to(
+            SystemAndNetworkSegmentToLocationSupplier.class).in(
+            Scopes.SINGLETON);
+   }
 
-    @Override
-    protected void bindRetryHandlers() {
-        bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
-                FGCPRetryIfNotProxyAuthenticationFailureHandler.class);
-    }
+   @Override
+   protected void bindRetryHandlers() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
+            FGCPRetryIfNotProxyAuthenticationFailureHandler.class);
+   }
 
-    @Override
-    protected void configure() {
-        super.configure();
-        bind(XMLParser.class).to(FGCPJAXBParser.class);
-        bind(new TypeLiteral<Supplier<SSLContext>>() {
-        }).to(new TypeLiteral<SSLContextWithKeysSupplier>() {
-        });
-    }
+   @Override
+   protected void configure() {
+      super.configure();
+      bind(XMLParser.class).to(FGCPJAXBParser.class);
+      bind(new TypeLiteral<Supplier<SSLContext>>() {
+      }).to(new TypeLiteral<SSLContextWithKeysSupplier>() {
+      });
+   }
 
-    @Provides
-    @TimeStamp
-    protected Calendar provideCalendar() {
-        return Calendar.getInstance();
-    }
+   @Provides
+   @TimeStamp
+   protected Calendar provideCalendar() {
+      return Calendar.getInstance();
+   }
 
-    /*
-     * 
-     * @Provides
-     * 
-     * @Singleton protected KeyStore
-     * provideKeyStore(@Named(Constants.PROPERTY_IDENTITY) String
-     * keyStoreFilename, @Named(Constants.PROPERTY_CREDENTIAL) String
-     * keyStorePassword) throws KeyStoreException { KeyStore keyStore =
-     * KeyStore.getInstance("pkcs12");
-     * 
-     * try { FileInputStream is = new
-     * FileInputStream(checkNotNull(keyStoreFilename,
-     * Constants.PROPERTY_IDENTITY)); keyStore.load(is,
-     * checkNotNull(keyStorePassword,
-     * Constants.PROPERTY_CREDENTIAL).toCharArray()); } catch (Exception e) { //
-     * expecting IOException, NoSuchAlgorithmException, CertificateException
-     * logger.error(e, "Keystore could not be opened: %s", keyStoreFilename); }
-     * return keyStore; }
-     * 
-     * @Provides
-     * 
-     * @Singleton protected PrivateKey provideKey(Provider<KeyStore>
-     * keyStoreProvider, @Named(Constants.PROPERTY_CREDENTIAL) String
-     * keyPassword) throws KeyStoreException, NoSuchAlgorithmException,
-     * UnrecoverableKeyException { KeyStore keyStore = keyStoreProvider.get();
-     * if (keyStore == null) return null;
-     * 
-     * // retrieving 1st alias in keystore as expecting only one String alias =
-     * checkNotNull(keyStore.aliases().nextElement(),
-     * "first alias in keystore"); return (PrivateKey) keyStore.getKey(alias,
-     * checkNotNull(keyPassword, Constants.PROPERTY_CREDENTIAL).toCharArray());
-     * }
-     */
-    /*
-     * maybe we can provide two authentication methods:
-     * 
-     * 1. same as DeltaCloud: User passes a folder name as identity and cert
-     * password as credential Note: pass relative path (e.g. cert's path:
-     * c:\jclouds\certs\dkoper\UserCert.p12: user passes 'dkoper': provider
-     * impl. finds it under e.g. $USER_DIR or $CURRENT_DIR or pass absolute path
-     * 2. no file access for GAE: User passes cert in PEM format (converted from
-     * UserCert.p12 using openssl?) as identity and cert password as credential
-     */
-    @Provides
-    @Singleton
-    protected KeyStore provideKeyStore(Crypto crypto, @Identity String cert,
-            @Credential String keyStorePassword) {
-        KeyStore keyStore = null;
-        try {
-            keyStore = KeyStore.getInstance("PKCS12");
+   /*
+    * 
+    * @Provides
+    * 
+    * @Singleton protected KeyStore
+    * provideKeyStore(@Named(Constants.PROPERTY_IDENTITY) String
+    * keyStoreFilename, @Named(Constants.PROPERTY_CREDENTIAL) String
+    * keyStorePassword) throws KeyStoreException { KeyStore keyStore =
+    * KeyStore.getInstance("pkcs12");
+    * 
+    * try { FileInputStream is = new
+    * FileInputStream(checkNotNull(keyStoreFilename,
+    * Constants.PROPERTY_IDENTITY)); keyStore.load(is,
+    * checkNotNull(keyStorePassword,
+    * Constants.PROPERTY_CREDENTIAL).toCharArray()); } catch (Exception e) { //
+    * expecting IOException, NoSuchAlgorithmException, CertificateException
+    * logger.error(e, "Keystore could not be opened: %s", keyStoreFilename); }
+    * return keyStore; }
+    * 
+    * @Provides
+    * 
+    * @Singleton protected PrivateKey provideKey(Provider<KeyStore>
+    * keyStoreProvider, @Named(Constants.PROPERTY_CREDENTIAL) String
+    * keyPassword) throws KeyStoreException, NoSuchAlgorithmException,
+    * UnrecoverableKeyException { KeyStore keyStore = keyStoreProvider.get();
+    * if (keyStore == null) return null;
+    * 
+    * // retrieving 1st alias in keystore as expecting only one String alias =
+    * checkNotNull(keyStore.aliases().nextElement(),
+    * "first alias in keystore"); return (PrivateKey) keyStore.getKey(alias,
+    * checkNotNull(keyPassword, Constants.PROPERTY_CREDENTIAL).toCharArray());
+    * }
+    */
+   /*
+    * maybe we can provide two authentication methods:
+    * 
+    * 1. same as DeltaCloud: User passes a folder name as identity and cert
+    * password as credential Note: pass relative path (e.g. cert's path:
+    * c:\jclouds\certs\dkoper\UserCert.p12: user passes 'dkoper': provider
+    * impl. finds it under e.g. $USER_DIR or $CURRENT_DIR or pass absolute path
+    * 2. no file access for GAE: User passes cert in PEM format (converted from
+    * UserCert.p12 using openssl?) as identity and cert password as credential
+    */
+   @Provides
+   @Singleton
+   protected KeyStore provideKeyStore(Crypto crypto, @Identity String cert,
+         @Credential String keyStorePassword) {
+      KeyStore keyStore = null;
+      try {
+         keyStore = KeyStore.getInstance("PKCS12");
 
-            // System.out.println("cert: " + cert);
-            // System.out.println("pwd : " + keyStorePassword);
-            File certFile = new File(checkNotNull(cert));
-            if (certFile.isFile()) { // cert is path to pkcs12 file
+         // System.out.println("cert: " + cert);
+         // System.out.println("pwd : " + keyStorePassword);
+         File certFile = new File(checkNotNull(cert));
+         if (certFile.isFile()) { // cert is path to pkcs12 file
 
-                keyStore.load(new FileInputStream(certFile),
-                        keyStorePassword.toCharArray());
-            } else { // cert is PEM encoded, containing private key and certs
+            keyStore.load(new FileInputStream(certFile),
+                  keyStorePassword.toCharArray());
+         } else { // cert is PEM encoded, containing private key and certs
 
-                // System.out.println("cert:\n" + cert);
-                // split in private key and certs
-                int privateKeyBeginIdx = cert.indexOf("-----BEGIN PRIVATE KEY");
-                int privateKeyEndIdx = cert.indexOf("-----END PRIVATE KEY");
-                String pemPrivateKey = cert.substring(privateKeyBeginIdx,
-                        privateKeyEndIdx + 26);
-                // System.out.println("***************");
-                // System.out.println("pemPrivateKey:\n" + pemPrivateKey);
-                // System.out.println("***************");
+            // System.out.println("cert:\n" + cert);
+            // split in private key and certs
+            int privateKeyBeginIdx = cert.indexOf("-----BEGIN PRIVATE KEY");
+            int privateKeyEndIdx = cert.indexOf("-----END PRIVATE KEY");
+            String pemPrivateKey = cert.substring(privateKeyBeginIdx,
+                  privateKeyEndIdx + 26);
+            // System.out.println("***************");
+            // System.out.println("pemPrivateKey:\n" + pemPrivateKey);
+            // System.out.println("***************");
 
-                String pemCerts = "";
-                int certsBeginIdx = 0;
+            String pemCerts = "";
+            int certsBeginIdx = 0;
 
-                do {
-                    certsBeginIdx = cert.indexOf("-----BEGIN CERTIFICATE",
-                            certsBeginIdx);
-                    // System.out.println("begin:" + certsBeginIdx);
+            do {
+               certsBeginIdx = cert.indexOf("-----BEGIN CERTIFICATE",
+                     certsBeginIdx);
+               // System.out.println("begin:" + certsBeginIdx);
 
-                    if (certsBeginIdx >= 0) {
-                        int certsEndIdx = cert.indexOf("-----END CERTIFICATE",
-                                certsBeginIdx) + 26;
-                        // System.out.println("end  :" + certsEndIdx);
-                        pemCerts += cert.substring(certsBeginIdx, certsEndIdx);
-                        certsBeginIdx = certsEndIdx;
-                    }
-                } while (certsBeginIdx != -1);
-                // System.out.println("***************");
-                // System.out.println("pemCerts:\n" + pemCerts);
-                // System.out.println("***************");
+               if (certsBeginIdx >= 0) {
+                  int certsEndIdx = cert.indexOf("-----END CERTIFICATE",
+                        certsBeginIdx) + 26;
+                  // System.out.println("end  :" + certsEndIdx);
+                  pemCerts += cert.substring(certsBeginIdx, certsEndIdx);
+                  certsBeginIdx = certsEndIdx;
+               }
+            } while (certsBeginIdx != -1);
+            // System.out.println("***************");
+            // System.out.println("pemCerts:\n" + pemCerts);
+            // System.out.println("***************");
 
-                /*
-                 * String pemCerts = "-----BEGIN "; Splitter pemSplitter =
-                 * Splitter.on("-----BEGIN ");
-                 * 
-                 * for (String part : pemSplitter.split(cert)) {
-                 * System.out.println("***************");
-                 * System.out.println("Part:\n" + part);
-                 * System.out.println("***************");
-                 * 
-                 * if (part.startsWith("PRIVATE KEY")
-                 */
-                /* || part.startsWith("RSA PRIVATE KEY)" *//*
-                                                            * ) {
-                                                            * 
-                                                            * int certEndIdx =
-                                                            * part.lastIndexOf
-                                                            * ("-----END");
-                                                            * pemPrivateKey +=
-                                                            * part.substring(0,
-                                                            * certEndIdx + 26);
-                                                            * // take up to next
-                                                            * "-----" (i.e.
-                                                            * "-----END") //
-                                                            * Splitter
-                                                            * keySplitter =
-                                                            * Splitter
-                                                            * .on("-----").
-                                                            * omitEmptyStrings
-                                                            * ().trimResults();
-                                                            * //
-                                                            * Iterator<String>
-                                                            * iter =
-                                                            * keySplitter.
-                                                            * split(part
-                                                            * ).iterator(); //
-                                                            * String keyName =
-                                                            * iter.next() +
-                                                            * "-----\n"; //
-                                                            * pemPrivateKey +=
-                                                            * keyName; ////
-                                                            * System.out
-                                                            * .println
-                                                            * ("Skipping: '" +
-                                                            * iter.next() +
-                                                            * "'"); //
-                                                            * pemPrivateKey +=
-                                                            * iter.next(); //
-                                                            * pemPrivateKey +=
-                                                            * "\n-----END " +
-                                                            * keyName;
-                                                            * System.out.println
-                                                            * (
-                                                            * "/////////////////"
-                                                            * );
-                                                            * System.out.println
-                                                            * (
-                                                            * "pemPrivateKey:\n"
-                                                            * + pemPrivateKey);
-                                                            * System
-                                                            * .out.println(
-                                                            * "/////////////////"
-                                                            * ); } else if
-                                                            * (part.startsWith
-                                                            * ("CERTIFICATE")) {
-                                                            * 
-                                                            * // take up to next
-                                                            * "-----" (i.e.
-                                                            * "-----END") // or
-                                                            * take up to last
-                                                            * END CERTIFICATE?
-                                                            * int certEndIdx =
-                                                            * part.lastIndexOf (
-                                                            * "----- END CERTIFICATE"
-                                                            * ); // pemCerts +=
-                                                            * part. // Splitter
-                                                            * keySplitter =
-                                                            * Splitter
-                                                            * .on("-----").
-                                                            * omitEmptyStrings
-                                                            * (); // pemCerts +=
-                                                            * keySplitter
-                                                            * .split(part)
-                                                            * .iterator
-                                                            * ().next(); //
-                                                            * pemCerts +=
-                                                            * "-----BEGIN "; }
-                                                            * else { // ignore
-                                                            * the fluff in
-                                                            * between (Bag
-                                                            * Attributes, etc.)
-                                                            * } }
-                                                            */
-
-                // parse private key
-                KeySpec keySpec = Pems.privateKeySpec(InputSuppliers
-                        .of(pemPrivateKey));
-                PrivateKey privateKey = crypto.rsaKeyFactory().generatePrivate(
-                        keySpec);
-
-                // populate keystore with private key and certs
-                CertificateFactory cf = CertificateFactory.getInstance("X.509");
-                @SuppressWarnings("unchecked")
-                Collection<Certificate> certs = (Collection<Certificate>) cf
-                        .generateCertificates(new ByteArrayInputStream(pemCerts
-                                .getBytes("UTF-8")));
-                keyStore.load(null);
-                keyStore.setKeyEntry("dummy", privateKey,
-                        keyStorePassword.toCharArray(),
-                        certs.toArray(new java.security.cert.Certificate[0]));
-
-                // System.out.println("private key: " + privateKey.getFormat() +
-                // "; "
-                // + privateKey.getAlgorithm() + "; class: " +
-                // privateKey.getClass().getName());// + "; " + new
-                // String(privateKey.getEncoded()));
-
-            }
-        } catch (Exception e) {
             /*
-             * KeyStoreException, IOException, NoSuchAlgorithmException,
-             * CertificateException, InvalidKeySpecException
+             * String pemCerts = "-----BEGIN "; Splitter pemSplitter =
+             * Splitter.on("-----BEGIN ");
+             * 
+             * for (String part : pemSplitter.split(cert)) {
+             * System.out.println("***************");
+             * System.out.println("Part:\n" + part);
+             * System.out.println("***************");
+             * 
+             * if (part.startsWith("PRIVATE KEY")
              */
-            throw new AuthorizationException("Error loading certificate", e);
-        }
+            /* || part.startsWith("RSA PRIVATE KEY)" *//*
+                                             * ) {
+                                             * 
+                                             * int certEndIdx =
+                                             * part.lastIndexOf
+                                             * ("-----END");
+                                             * pemPrivateKey +=
+                                             * part.substring(0,
+                                             * certEndIdx + 26);
+                                             * // take up to next
+                                             * "-----" (i.e.
+                                             * "-----END") //
+                                             * Splitter
+                                             * keySplitter =
+                                             * Splitter
+                                             * .on("-----").
+                                             * omitEmptyStrings
+                                             * ().trimResults();
+                                             * //
+                                             * Iterator<String>
+                                             * iter =
+                                             * keySplitter.
+                                             * split(part
+                                             * ).iterator(); //
+                                             * String keyName =
+                                             * iter.next() +
+                                             * "-----\n"; //
+                                             * pemPrivateKey +=
+                                             * keyName; ////
+                                             * System.out
+                                             * .println
+                                             * ("Skipping: '" +
+                                             * iter.next() +
+                                             * "'"); //
+                                             * pemPrivateKey +=
+                                             * iter.next(); //
+                                             * pemPrivateKey +=
+                                             * "\n-----END " +
+                                             * keyName;
+                                             * System.out.println
+                                             * (
+                                             * "/////////////////"
+                                             * );
+                                             * System.out.println
+                                             * (
+                                             * "pemPrivateKey:\n"
+                                             * + pemPrivateKey);
+                                             * System
+                                             * .out.println(
+                                             * "/////////////////"
+                                             * ); } else if
+                                             * (part.startsWith
+                                             * ("CERTIFICATE")) {
+                                             * 
+                                             * // take up to next
+                                             * "-----" (i.e.
+                                             * "-----END") // or
+                                             * take up to last
+                                             * END CERTIFICATE?
+                                             * int certEndIdx =
+                                             * part.lastIndexOf (
+                                             * "----- END CERTIFICATE"
+                                             * ); // pemCerts +=
+                                             * part. // Splitter
+                                             * keySplitter =
+                                             * Splitter
+                                             * .on("-----").
+                                             * omitEmptyStrings
+                                             * (); // pemCerts +=
+                                             * keySplitter
+                                             * .split(part)
+                                             * .iterator
+                                             * ().next(); //
+                                             * pemCerts +=
+                                             * "-----BEGIN "; }
+                                             * else { // ignore
+                                             * the fluff in
+                                             * between (Bag
+                                             * Attributes, etc.)
+                                             * } }
+                                             */
 
-        return keyStore;
-    }
+            // parse private key
+            KeySpec keySpec = Pems.privateKeySpec(InputSuppliers
+                  .of(pemPrivateKey));
+            PrivateKey privateKey = crypto.rsaKeyFactory().generatePrivate(
+                  keySpec);
+
+            // populate keystore with private key and certs
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            @SuppressWarnings("unchecked")
+            Collection<Certificate> certs = (Collection<Certificate>) cf
+                  .generateCertificates(new ByteArrayInputStream(pemCerts
+                        .getBytes("UTF-8")));
+            keyStore.load(null);
+            keyStore.setKeyEntry("dummy", privateKey,
+                  keyStorePassword.toCharArray(),
+                  certs.toArray(new java.security.cert.Certificate[0]));
+
+            // System.out.println("private key: " + privateKey.getFormat() +
+            // "; "
+            // + privateKey.getAlgorithm() + "; class: " +
+            // privateKey.getClass().getName());// + "; " + new
+            // String(privateKey.getEncoded()));
+
+         }
+      } catch (Exception e) {
+         /*
+          * KeyStoreException, IOException, NoSuchAlgorithmException,
+          * CertificateException, InvalidKeySpecException
+          */
+         throw new AuthorizationException("Error loading certificate", e);
+      }
+
+      return keyStore;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPComputeServiceContextModule.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPComputeServiceContextModule.java
index 46f3646..1c6d29f 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPComputeServiceContextModule.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPComputeServiceContextModule.java
@@ -53,88 +53,88 @@
  * @author Dies Koper
  */
 public class FGCPComputeServiceContextModule
-        extends
-        ComputeServiceAdapterContextModule<VServerMetadata, ServerType, DiskImage, Location> {
+      extends
+      ComputeServiceAdapterContextModule<VServerMetadata, ServerType, DiskImage, Location> {
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected void configure() {
-        super.configure();
-        // installDependencies();
+   @SuppressWarnings({ "unchecked", "rawtypes" })
+   @Override
+   protected void configure() {
+      super.configure();
+      // installDependencies();
 
-        bind(
-                new TypeLiteral<ComputeServiceAdapter<VServerMetadata, ServerType, DiskImage, Location>>() {
-                }).to(FGCPComputeServiceAdapter.class);
+      bind(
+            new TypeLiteral<ComputeServiceAdapter<VServerMetadata, ServerType, DiskImage, Location>>() {
+            }).to(FGCPComputeServiceAdapter.class);
 
-        // the following bind functions that map FGCP domain specific resources
-        // to jclouds'
-        bind(new TypeLiteral<Function<VServerMetadata, NodeMetadata>>() {
-        }).to(VServerMetadataToNodeMetadata.class);
-        bind(new TypeLiteral<Function<DiskImage, Image>>() {
-        }).to(DiskImageToImage.class);
-        bind(new TypeLiteral<Function<DiskImage, OperatingSystem>>() {
-        }).to(DiskImageToOperatingSystem.class);
-        bind(new TypeLiteral<Function<ServerType, Hardware>>() {
-        }).to(ServerTypeToHardware.class);
-        bind(new TypeLiteral<Function<Disk, Volume>>() {
-        }).to(DiskToVolume.class);
-        bind(new TypeLiteral<Function<CPU, Processor>>() {
-        }).to(CPUToProcessor.class);
+      // the following bind functions that map FGCP domain specific resources
+      // to jclouds'
+      bind(new TypeLiteral<Function<VServerMetadata, NodeMetadata>>() {
+      }).to(VServerMetadataToNodeMetadata.class);
+      bind(new TypeLiteral<Function<DiskImage, Image>>() {
+      }).to(DiskImageToImage.class);
+      bind(new TypeLiteral<Function<DiskImage, OperatingSystem>>() {
+      }).to(DiskImageToOperatingSystem.class);
+      bind(new TypeLiteral<Function<ServerType, Hardware>>() {
+      }).to(ServerTypeToHardware.class);
+      bind(new TypeLiteral<Function<Disk, Volume>>() {
+      }).to(DiskToVolume.class);
+      bind(new TypeLiteral<Function<CPU, Processor>>() {
+      }).to(CPUToProcessor.class);
 
-        // we aren't converting hardware from a provider-specific type
-        bind(new TypeLiteral<Function<Location, Location>>() {
-        }).to((Class) IdentityFunction.class);
-        bind(new TypeLiteral<Function<Hardware, Hardware>>() {
-        }).to((Class) IdentityFunction.class);
+      // we aren't converting hardware from a provider-specific type
+      bind(new TypeLiteral<Function<Location, Location>>() {
+      }).to((Class) IdentityFunction.class);
+      bind(new TypeLiteral<Function<Hardware, Hardware>>() {
+      }).to((Class) IdentityFunction.class);
 
-        bind(TemplateOptions.class).to(FGCPTemplateOptions.class);
+      bind(TemplateOptions.class).to(FGCPTemplateOptions.class);
 
 
-        // bind(new TypeLiteral<Predicate<String>>() {
-        // }).to((Class) ServerStopped.class);
+      // bind(new TypeLiteral<Predicate<String>>() {
+      // }).to((Class) ServerStopped.class);
 
-        // need to look into the following later for to map (create) jclouds'
-        // location to FGCP.
-        // see LocationScope:
-        // PROVIDER: FGCP
-        // REGION: country?/country+state?
-        // ZONE: virtual DC: contractId
-        // NETWORK: VSYS? DMZ/SECURE1/SECURE2?
-        // RACK: N/A?
-        // HOST: N/A?
-        // there are no locations except the provider
-        // bind(new TypeLiteral<Supplier<Location>>() {
-        // }).to(OnlyLocationOrFirstZone.class);
+      // need to look into the following later for to map (create) jclouds'
+      // location to FGCP.
+      // see LocationScope:
+      // PROVIDER: FGCP
+      // REGION: country?/country+state?
+      // ZONE: virtual DC: contractId
+      // NETWORK: VSYS? DMZ/SECURE1/SECURE2?
+      // RACK: N/A?
+      // HOST: N/A?
+      // there are no locations except the provider
+      // bind(new TypeLiteral<Supplier<Location>>() {
+      // }).to(OnlyLocationOrFirstZone.class);
 
-        // install(new FGCPBindComputeStrategiesByClass());
-        // install(new FGCPBindComputeSuppliersByClass());
-        // bind(ReviseParsedImage.class).to(AWSEC2ReviseParsedImage.class);
-        // bind(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class).to(
-        // CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class);
-        // bind(EC2HardwareSupplier.class).to(AWSEC2HardwareSupplier.class);
-        // bind(EC2TemplateBuilderImpl.class).to(AWSEC2TemplateBuilderImpl.class);
-        // bind(EC2GetNodeMetadataStrategy.class).to(AWSEC2GetNodeMetadataStrategy.class);
-        // bind(InstancePresent.class).to(AWSEC2InstancePresent.class);
-        // bind(EC2CreateNodesInGroupThenAddToSet.class).to(AWSEC2CreateNodesInGroupThenAddToSet.class);
-        // bind(RunningInstanceToNodeMetadata.class).to(AWSRunningInstanceToNodeMetadata.class);
-    }
+      // install(new FGCPBindComputeStrategiesByClass());
+      // install(new FGCPBindComputeSuppliersByClass());
+      // bind(ReviseParsedImage.class).to(AWSEC2ReviseParsedImage.class);
+      // bind(CreateKeyPairAndSecurityGroupsAsNeededAndReturnRunOptions.class).to(
+      // CreateKeyPairPlacementAndSecurityGroupsAsNeededAndReturnRunOptions.class);
+      // bind(EC2HardwareSupplier.class).to(AWSEC2HardwareSupplier.class);
+      // bind(EC2TemplateBuilderImpl.class).to(AWSEC2TemplateBuilderImpl.class);
+      // bind(EC2GetNodeMetadataStrategy.class).to(AWSEC2GetNodeMetadataStrategy.class);
+      // bind(InstancePresent.class).to(AWSEC2InstancePresent.class);
+      // bind(EC2CreateNodesInGroupThenAddToSet.class).to(AWSEC2CreateNodesInGroupThenAddToSet.class);
+      // bind(RunningInstanceToNodeMetadata.class).to(AWSRunningInstanceToNodeMetadata.class);
+   }
 
-    // @Provides
-    // @Singleton
-    // @Named("SECURITY")
-    // protected Predicate<String> provideServerStopped(ServerStopped
-    // serverStopped, Timeouts timeouts) {
-    // return new RetryablePredicate<String>(serverStopped,
-    // timeouts.nodeSuspended);
-    // }
+   // @Provides
+   // @Singleton
+   // @Named("SECURITY")
+   // protected Predicate<String> provideServerStopped(ServerStopped
+   // serverStopped, Timeouts timeouts) {
+   // return new RetryablePredicate<String>(serverStopped,
+   // timeouts.nodeSuspended);
+   // }
 
-    protected void installDependencies() {
-        // install(new FGCPComputeServiceDependenciesModule());
-    }
+   protected void installDependencies() {
+      // install(new FGCPComputeServiceDependenciesModule());
+   }
 
-    /*
-     * @Override protected TemplateBuilder provideTemplate(Injector injector,
-     * TemplateBuilder template) { return
-     * template.osFamily(CENTOS).os64Bit(true); }
-     */
+   /*
+    * @Override protected TemplateBuilder provideTemplate(Injector injector,
+    * TemplateBuilder template) { return
+    * template.osFamily(CENTOS).os64Bit(true); }
+    */
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/CPUToProcessor.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/CPUToProcessor.java
index a26508e..63079a7 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/CPUToProcessor.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/CPUToProcessor.java
@@ -20,11 +20,12 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.base.Function;
+import javax.inject.Singleton;
+
 import org.jclouds.compute.domain.Processor;
 import org.jclouds.fujitsu.fgcp.domain.CPU;
 
-import javax.inject.Singleton;
+import com.google.common.base.Function;
 
 /**
  * Created by IntelliJ IDEA.
@@ -34,11 +35,11 @@
 @Singleton
 public class CPUToProcessor implements Function<CPU, Processor> {
 
-    @Override
-    public Processor apply(CPU cpu) {
-        checkNotNull(cpu, "cpu");
+   @Override
+   public Processor apply(CPU cpu) {
+      checkNotNull(cpu, "cpu");
 
-        return new Processor(Double.valueOf(cpu.getCores()), Double.valueOf(cpu
-                .getSpeedPerCore()));
-    }
+      return new Processor(Double.valueOf(cpu.getCores()), Double.valueOf(cpu
+            .getSpeedPerCore()));
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToImage.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToImage.java
index e5200da..8ea67fe 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToImage.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToImage.java
@@ -43,38 +43,38 @@
 @Singleton
 public class DiskImageToImage implements Function<DiskImage, Image> {
 
-    private final DiskImageToOperatingSystem diskImageToOperatingSystem;
-    private final RegionToProviderOrJustProvider regionSupplier;
+   private final DiskImageToOperatingSystem diskImageToOperatingSystem;
+   private final RegionToProviderOrJustProvider regionSupplier;
 
-    @Inject
-    public DiskImageToImage(
-            DiskImageToOperatingSystem diskImageToOperatingSystem,
-            RegionToProviderOrJustProvider locationSupplier) {
-        this.diskImageToOperatingSystem = checkNotNull(
-                diskImageToOperatingSystem, "diskImageToOperatingSystem");
-        this.regionSupplier = checkNotNull(locationSupplier, "locationProvider");
-    }
+   @Inject
+   public DiskImageToImage(
+         DiskImageToOperatingSystem diskImageToOperatingSystem,
+         RegionToProviderOrJustProvider locationSupplier) {
+      this.diskImageToOperatingSystem = checkNotNull(
+            diskImageToOperatingSystem, "diskImageToOperatingSystem");
+      this.regionSupplier = checkNotNull(locationSupplier, "locationProvider");
+   }
 
-    @Override
-    public Image apply(DiskImage from) {
-        checkNotNull(from, "disk image");
+   @Override
+   public Image apply(DiskImage from) {
+      checkNotNull(from, "disk image");
 
-        ImageBuilder builder = new ImageBuilder();
+      ImageBuilder builder = new ImageBuilder();
 
-        builder.ids(from.getId());
-        builder.name(from.getName());
-        builder.description(from.getDescription());
-        builder.location(Iterables.getOnlyElement(regionSupplier.get()));
-        // in fgcp, if the image is listed it is available
-        builder.status(Status.AVAILABLE);
+      builder.ids(from.getId());
+      builder.name(from.getName());
+      builder.description(from.getDescription());
+      builder.location(Iterables.getOnlyElement(regionSupplier.get()));
+      // in fgcp, if the image is listed it is available
+      builder.status(Status.AVAILABLE);
 
-        OperatingSystem os = diskImageToOperatingSystem.apply(from);
-        builder.operatingSystem(os);
-        String user = os.getFamily() == OsFamily.WINDOWS ? "Administrator"
-                : "root";
-        builder.defaultCredentials(LoginCredentials.builder().identity(user)
-                .noPassword().build());
+      OperatingSystem os = diskImageToOperatingSystem.apply(from);
+      builder.operatingSystem(os);
+      String user = os.getFamily() == OsFamily.WINDOWS ? "Administrator"
+            : "root";
+      builder.defaultCredentials(LoginCredentials.builder().identity(user)
+            .noPassword().build());
 
-        return builder.build();
-    }
+      return builder.build();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToOperatingSystem.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToOperatingSystem.java
index b1ce9a1..eeab199 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToOperatingSystem.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToOperatingSystem.java
@@ -38,36 +38,36 @@
  */
 @Singleton
 public class DiskImageToOperatingSystem implements
-        Function<DiskImage, OperatingSystem> {
+      Function<DiskImage, OperatingSystem> {
 
-    private static final Pattern OS_VERSION_PATTERN = Pattern
-            .compile("^.*?(\\d.*)\\s(32|64).*$");
+   private static final Pattern OS_VERSION_PATTERN = Pattern
+         .compile("^.*?(\\d.*)\\s(32|64).*$");
 
-    @Override
-    public OperatingSystem apply(DiskImage image) {
-        checkNotNull(image, "disk image");
+   @Override
+   public OperatingSystem apply(DiskImage image) {
+      checkNotNull(image, "disk image");
 
-        // convert to short name rhel to accommodate ComputeServiceUtils
-        // conventions
-        String shortOsName = image.getOsName().replace(
-                "Red Hat Enterprise Linux", "rhel");
-        OsFamily osFamily = ComputeServiceUtils
-                .parseOsFamilyOrUnrecognized(shortOsName);
-        OperatingSystem.Builder builder = OperatingSystem.builder();
+      // convert to short name rhel to accommodate ComputeServiceUtils
+      // conventions
+      String shortOsName = image.getOsName().replace(
+            "Red Hat Enterprise Linux", "rhel");
+      OsFamily osFamily = ComputeServiceUtils
+            .parseOsFamilyOrUnrecognized(shortOsName);
+      OperatingSystem.Builder builder = OperatingSystem.builder();
 
-        builder.name(image.getOsName());
-        builder.family(osFamily);
-        builder.is64Bit(image.getOsName().contains("64bit")
-                || image.getOsName().contains("64 bit")
-                || image.getOsName().contains("x64"));
-        // OsType returns guest type (hvm, pv), which aws-ec2 is mapping to arch
-        builder.arch(image.getOsType());
-        Matcher m = OS_VERSION_PATTERN.matcher(image.getOsName());
-        if (m.matches()) {
-            builder.version(m.group(1));
-        }
-        builder.description(image.getOsName());
+      builder.name(image.getOsName());
+      builder.family(osFamily);
+      builder.is64Bit(image.getOsName().contains("64bit")
+            || image.getOsName().contains("64 bit")
+            || image.getOsName().contains("x64"));
+      // OsType returns guest type (hvm, pv), which aws-ec2 is mapping to arch
+      builder.arch(image.getOsType());
+      Matcher m = OS_VERSION_PATTERN.matcher(image.getOsName());
+      if (m.matches()) {
+         builder.version(m.group(1));
+      }
+      builder.description(image.getOsName());
 
-        return builder.build();
-    }
+      return builder.build();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskToVolume.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskToVolume.java
index c9f4067..e218cf0 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskToVolume.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskToVolume.java
@@ -20,12 +20,13 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.base.Function;
+import javax.inject.Singleton;
+
 import org.jclouds.compute.domain.Volume;
 import org.jclouds.compute.domain.VolumeBuilder;
 import org.jclouds.fujitsu.fgcp.domain.Disk;
 
-import javax.inject.Singleton;
+import com.google.common.base.Function;
 
 /**
  * Created by IntelliJ IDEA.
@@ -35,19 +36,19 @@
 @Singleton
 public class DiskToVolume implements Function<Disk, Volume> {
 
-    @Override
-    public Volume apply(Disk disk) {
-        checkNotNull(disk, "disk");
+   @Override
+   public Volume apply(Disk disk) {
+      checkNotNull(disk, "disk");
 
-        VolumeBuilder builder = new VolumeBuilder();
+      VolumeBuilder builder = new VolumeBuilder();
 
-        builder.size(1000f * Float.valueOf(disk.getSize()));
-        // "Disk"'s are additional disks; they can't be booted disk(?)
-        builder.bootDevice(false);
-        builder.durable(true);
-        builder.type(Volume.Type.SAN);
-        builder.id("type: " + disk.getType() + " usage: " + disk.getUsage());
+      builder.size(1000f * Float.valueOf(disk.getSize()));
+      // "Disk"'s are additional disks; they can't be booted disk(?)
+      builder.bootDevice(false);
+      builder.durable(true);
+      builder.type(Volume.Type.SAN);
+      builder.id("type: " + disk.getType() + " usage: " + disk.getUsage());
 
-        return builder.build();
-    }
+      return builder.build();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ResourceIdToFirewallId.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ResourceIdToFirewallId.java
index 2e91f2b..82beebb 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ResourceIdToFirewallId.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ResourceIdToFirewallId.java
@@ -34,18 +34,18 @@
 @Singleton
 public class ResourceIdToFirewallId implements Function<String, String> {
 
-    private ResourceIdToSystemId toSystemId;
+   private ResourceIdToSystemId toSystemId;
 
-    @Inject
-    private ResourceIdToFirewallId(ResourceIdToSystemId resourceIdToSystemId) {
-        this.toSystemId = checkNotNull(resourceIdToSystemId,
-                "resourceIdToSystemId");
-    }
+   @Inject
+   private ResourceIdToFirewallId(ResourceIdToSystemId resourceIdToSystemId) {
+      this.toSystemId = checkNotNull(resourceIdToSystemId,
+            "resourceIdToSystemId");
+   }
 
-    @Override
-    public String apply(String id) {
-        checkNotNull(id, "resource id");
+   @Override
+   public String apply(String id) {
+      checkNotNull(id, "resource id");
 
-        return toSystemId.apply(id) + "-S-0001";
-    }
+      return toSystemId.apply(id) + "-S-0001";
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ResourceIdToSystemId.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ResourceIdToSystemId.java
index 01b1891..229a236 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ResourceIdToSystemId.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ResourceIdToSystemId.java
@@ -37,16 +37,16 @@
 @Singleton
 public class ResourceIdToSystemId implements Function<String, String> {
 
-    @Override
-    public String apply(String id) {
-        checkNotNull(id, "resource id");
+   @Override
+   public String apply(String id) {
+      checkNotNull(id, "resource id");
 
-        Pattern pattern = Pattern.compile("^(\\w+-\\w+)\\b.*");
-        Matcher matcher = pattern.matcher((String) id);
+      Pattern pattern = Pattern.compile("^(\\w+-\\w+)\\b.*");
+      Matcher matcher = pattern.matcher((String) id);
 
-        checkArgument(matcher.find(),
-                "no valid resource id found: " + id.toString());
+      checkArgument(matcher.find(),
+            "no valid resource id found: " + id.toString());
 
-        return matcher.group(1);
-    }
+      return matcher.group(1);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ServerTypeToHardware.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ServerTypeToHardware.java
index ec99cf5..fc0ed61 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ServerTypeToHardware.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/ServerTypeToHardware.java
@@ -39,30 +39,30 @@
  */
 @Singleton
 public class ServerTypeToHardware implements Function<ServerType, Hardware> {
-    private final CPUToProcessor cpuToProcessor;
-    private final DiskToVolume diskToVolume;
+   private final CPUToProcessor cpuToProcessor;
+   private final DiskToVolume diskToVolume;
 
-    @Inject
-    public ServerTypeToHardware(CPUToProcessor cpuToProcessor,
-            DiskToVolume diskToVolume) {
-        this.cpuToProcessor = checkNotNull(cpuToProcessor);
-        this.diskToVolume = checkNotNull(diskToVolume);
-    }
+   @Inject
+   public ServerTypeToHardware(CPUToProcessor cpuToProcessor,
+         DiskToVolume diskToVolume) {
+      this.cpuToProcessor = checkNotNull(cpuToProcessor);
+      this.diskToVolume = checkNotNull(diskToVolume);
+   }
 
-    @Override
-    public Hardware apply(ServerType from) {
-        checkNotNull(from, "ServerType");
-        HardwareBuilder builder = new HardwareBuilder();
+   @Override
+   public Hardware apply(ServerType from) {
+      checkNotNull(from, "ServerType");
+      HardwareBuilder builder = new HardwareBuilder();
 
-        builder.ids(from.getId());
-        builder.name(from.getName());
-        builder.ram((int) (1000d * Double.valueOf(from.getMemory().getSize())));
-        builder.processor(cpuToProcessor.apply(from.getCpu()));
-        builder.supportsImage(Predicates.<Image> alwaysTrue());
-        // all servers are 64bit. The OS however may be 32 bit.
-        builder.is64Bit(true);
-        builder.volumes(Iterables.transform(from.getDisks(), diskToVolume));
+      builder.ids(from.getId());
+      builder.name(from.getName());
+      builder.ram((int) (1000d * Double.valueOf(from.getMemory().getSize())));
+      builder.processor(cpuToProcessor.apply(from.getCpu()));
+      builder.supportsImage(Predicates.<Image> alwaysTrue());
+      // all servers are 64bit. The OS however may be 32 bit.
+      builder.is64Bit(true);
+      builder.volumes(Iterables.transform(from.getDisks(), diskToVolume));
 
-        return builder.build();
-    }
+      return builder.build();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/SingleElementResponseToElement.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/SingleElementResponseToElement.java
index b8677a4..3f672ad 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/SingleElementResponseToElement.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/SingleElementResponseToElement.java
@@ -25,10 +25,10 @@
 import com.google.common.base.Function;
 
 public class SingleElementResponseToElement implements
-        Function<SingleElementResponse, Object> {
+      Function<SingleElementResponse, Object> {
 
-    @Override
-    public Object apply(SingleElementResponse r) {
-        return checkNotNull(r, "response").getElement();
-    }
+   @Override
+   public Object apply(SingleElementResponse r) {
+      return checkNotNull(r, "response").getElement();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/VServerMetadataToNodeMetadata.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/VServerMetadataToNodeMetadata.java
index 66c390b..3da3d3e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/VServerMetadataToNodeMetadata.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/functions/VServerMetadataToNodeMetadata.java
@@ -59,187 +59,187 @@
  */
 @Singleton
 public class VServerMetadataToNodeMetadata implements
-        Function<VServerMetadata, NodeMetadata> {
+      Function<VServerMetadata, NodeMetadata> {
 
-    public static final Map<VServerStatus, Status> vServerToStatus = ImmutableMap
-            .<VServerStatus, Status> builder()
-            .put(VServerStatus.DEPLOYING, Status.PENDING)
-            .put(VServerStatus.RUNNING, Status.RUNNING)
-            .put(VServerStatus.STOPPING, Status.PENDING)
-            .put(VServerStatus.STOPPED, Status.SUSPENDED)
-            .put(VServerStatus.STARTING, Status.PENDING)
-            .put(VServerStatus.FAILOVER, Status.RUNNING)
-            .put(VServerStatus.UNEXPECTED_STOP, Status.SUSPENDED)
-            .put(VServerStatus.RESTORING, Status.PENDING)
-            .put(VServerStatus.BACKUP_ING, Status.PENDING)
-            .put(VServerStatus.ERROR, Status.ERROR)
-            .put(VServerStatus.START_ERROR, Status.ERROR)
-            .put(VServerStatus.STOP_ERROR, Status.ERROR)
-            .put(VServerStatus.CHANGE_TYPE, Status.PENDING)
-            .put(VServerStatus.REGISTERING, Status.PENDING)
-            .put(VServerStatus.UNRECOGNIZED, Status.UNRECOGNIZED).build();
+   public static final Map<VServerStatus, Status> vServerToStatus = ImmutableMap
+         .<VServerStatus, Status> builder()
+         .put(VServerStatus.DEPLOYING, Status.PENDING)
+         .put(VServerStatus.RUNNING, Status.RUNNING)
+         .put(VServerStatus.STOPPING, Status.PENDING)
+         .put(VServerStatus.STOPPED, Status.SUSPENDED)
+         .put(VServerStatus.STARTING, Status.PENDING)
+         .put(VServerStatus.FAILOVER, Status.RUNNING)
+         .put(VServerStatus.UNEXPECTED_STOP, Status.SUSPENDED)
+         .put(VServerStatus.RESTORING, Status.PENDING)
+         .put(VServerStatus.BACKUP_ING, Status.PENDING)
+         .put(VServerStatus.ERROR, Status.ERROR)
+         .put(VServerStatus.START_ERROR, Status.ERROR)
+         .put(VServerStatus.STOP_ERROR, Status.ERROR)
+         .put(VServerStatus.CHANGE_TYPE, Status.PENDING)
+         .put(VServerStatus.REGISTERING, Status.PENDING)
+         .put(VServerStatus.UNRECOGNIZED, Status.UNRECOGNIZED).build();
 
-    @Resource
-    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-    protected Logger logger = Logger.NULL;
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
 
-    protected final Supplier<Set<? extends Location>> locations;
-    protected final Supplier<Set<? extends Image>> images;
-    protected final Supplier<Set<? extends Hardware>> hardwares;
-    protected final GroupNamingConvention nodeNamingConvention;
+   protected final Supplier<Set<? extends Location>> locations;
+   protected final Supplier<Set<? extends Image>> images;
+   protected final Supplier<Set<? extends Hardware>> hardwares;
+   protected final GroupNamingConvention nodeNamingConvention;
 
-    private static class FindImageForVServer implements Predicate<Image> {
-        private final VServer server;
+   private static class FindImageForVServer implements Predicate<Image> {
+      private final VServer server;
 
-        private FindImageForVServer(VServer server) {
-            this.server = server;
-        }
+      private FindImageForVServer(VServer server) {
+         this.server = server;
+      }
 
-        @Override
-        public boolean apply(Image input) {
-            return input.getId().equals(server.getDiskimageId());
-        }
-    }
+      @Override
+      public boolean apply(Image input) {
+         return input.getId().equals(server.getDiskimageId());
+      }
+   }
 
-    protected Image parseImage(VServer from) {
-        try {
-            return Iterables.find(images.get(), new FindImageForVServer(from));
-        } catch (NoSuchElementException e) {
-            logger.warn("could not find a matching image for server %s", from);
-        }
-        return null;
-    }
+   protected Image parseImage(VServer from) {
+      try {
+         return Iterables.find(images.get(), new FindImageForVServer(from));
+      } catch (NoSuchElementException e) {
+         logger.warn("could not find a matching image for server %s", from);
+      }
+      return null;
+   }
 
-    private static class FindHardwareForServerType implements
-            Predicate<Hardware> {
-        private final String type;
+   private static class FindHardwareForServerType implements
+         Predicate<Hardware> {
+      private final String type;
 
-        private FindHardwareForServerType(String type) {
-            this.type = type;
-        }
+      private FindHardwareForServerType(String type) {
+         this.type = type;
+      }
 
-        @Override
-        public boolean apply(Hardware input) {
-            return input.getName().equals(type);
-        }
-    }
+      @Override
+      public boolean apply(Hardware input) {
+         return input.getName().equals(type);
+      }
+   }
 
-    protected Hardware parseHardware(String from) {
-        try {
-            return Iterables.find(hardwares.get(),
-                    new FindHardwareForServerType(from));
-        } catch (NoSuchElementException e) {
-            logger.warn(
-                    "could not find a matching hardware for server type %s",
-                    from);
-        }
-        return null;
-    }
+   protected Hardware parseHardware(String from) {
+      try {
+         return Iterables.find(hardwares.get(),
+               new FindHardwareForServerType(from));
+      } catch (NoSuchElementException e) {
+         logger.warn(
+               "could not find a matching hardware for server type %s",
+               from);
+      }
+      return null;
+   }
 
-    private static class FindLocationForVServer implements Predicate<Location> {
-        private final VServerWithVNICs server;
+   private static class FindLocationForVServer implements Predicate<Location> {
+      private final VServerWithVNICs server;
 
-        private FindLocationForVServer(VServerWithVNICs server) {
-            this.server = server;
-        }
+      private FindLocationForVServer(VServerWithVNICs server) {
+         this.server = server;
+      }
 
-        @Override
-        public boolean apply(Location input) {
-            return input.getId().equals(
-                    Iterables.getLast(server.getVnics()).getNetworkId());
-        }
-    }
+      @Override
+      public boolean apply(Location input) {
+         return input.getId().equals(
+               Iterables.getLast(server.getVnics()).getNetworkId());
+      }
+   }
 
-    protected Location parseLocation(VServerWithVNICs from) {
-        try {
-            return Iterables.find(locations.get(), new FindLocationForVServer(
-                    from));
-        } catch (NoSuchElementException e) {
-            logger.warn("could not find a matching realm for server %s", from);
-        }
-        return null;
-    }
+   protected Location parseLocation(VServerWithVNICs from) {
+      try {
+         return Iterables.find(locations.get(), new FindLocationForVServer(
+               from));
+      } catch (NoSuchElementException e) {
+         logger.warn("could not find a matching realm for server %s", from);
+      }
+      return null;
+   }
 
-    @Inject
-    VServerMetadataToNodeMetadata(
-            @Memoized Supplier<Set<? extends Location>> locations,
-            @Memoized Supplier<Set<? extends Image>> images,
-            @Memoized Supplier<Set<? extends Hardware>> hardwares,
-            GroupNamingConvention.Factory namingConvention) {
-        this.images = checkNotNull(images, "images");
-        this.locations = checkNotNull(locations, "locations");
-        this.hardwares = checkNotNull(hardwares, "hardwares");
-        this.nodeNamingConvention = checkNotNull(namingConvention,
-                "namingConvention").createWithoutPrefix();
-    }
+   @Inject
+   VServerMetadataToNodeMetadata(
+         @Memoized Supplier<Set<? extends Location>> locations,
+         @Memoized Supplier<Set<? extends Image>> images,
+         @Memoized Supplier<Set<? extends Hardware>> hardwares,
+         GroupNamingConvention.Factory namingConvention) {
+      this.images = checkNotNull(images, "images");
+      this.locations = checkNotNull(locations, "locations");
+      this.hardwares = checkNotNull(hardwares, "hardwares");
+      this.nodeNamingConvention = checkNotNull(namingConvention,
+            "namingConvention").createWithoutPrefix();
+   }
 
-    @Override
-    public NodeMetadata apply(VServerMetadata from) {
-        NodeMetadataBuilder builder = new NodeMetadataBuilder();
+   @Override
+   public NodeMetadata apply(VServerMetadata from) {
+      NodeMetadataBuilder builder = new NodeMetadataBuilder();
 
-        builder.ids(from.getId());
-        builder.name(from.getName());
-        builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from
-                .getName()));
-        if (from.getStatus() == null)
-            System.out.println("status null for: " + from.getId() + ": "
-                    + from.getName());
+      builder.ids(from.getId());
+      builder.name(from.getName());
+      builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from
+            .getName()));
+      if (from.getStatus() == null)
+         System.out.println("status null for: " + from.getId() + ": "
+               + from.getName());
 
-        builder.status(vServerToStatus.get(from.getStatus()));
-        builder.privateAddresses(ImmutableSet.<String> of());
-        builder.publicAddresses(ImmutableSet.<String> of());
+      builder.status(vServerToStatus.get(from.getStatus()));
+      builder.privateAddresses(ImmutableSet.<String> of());
+      builder.publicAddresses(ImmutableSet.<String> of());
 
-        //
-        // if (from.getIps() != null) {
-        //
-        // builder.publicAddresses(Collections2.transform(from.getIps(),
-        // new Function<PublicIP, String>() {
-        //
-        // @Override
-        // public String apply(PublicIP input) {
-        // return input.getAddress();
-        // }
-        //
-        // }));
-        // }
+      //
+      // if (from.getIps() != null) {
+      //
+      // builder.publicAddresses(Collections2.transform(from.getIps(),
+      // new Function<PublicIP, String>() {
+      //
+      // @Override
+      // public String apply(PublicIP input) {
+      // return input.getAddress();
+      // }
+      //
+      // }));
+      // }
 
-        if (from.getServer() != null) {
+      if (from.getServer() != null) {
 
-            builder.imageId(from.getServer().getDiskimageId());
-            builder.hardware(parseHardware(from.getServer().getType()));
+         builder.imageId(from.getServer().getDiskimageId());
+         builder.hardware(parseHardware(from.getServer().getType()));
 
-            LoginCredentials.Builder credentialsBuilder = LoginCredentials
-                    .builder().password(from.getInitialPassword());
+         LoginCredentials.Builder credentialsBuilder = LoginCredentials
+               .builder().password(from.getInitialPassword());
 
-            Image image = parseImage(from.getServer());
-            // image will not be found if server was created a while back and
-            // the image has since been destroyed or discontinued (like an old
-            // CentOS version)
-            if (image != null) {
+         Image image = parseImage(from.getServer());
+         // image will not be found if server was created a while back and
+         // the image has since been destroyed or discontinued (like an old
+         // CentOS version)
+         if (image != null) {
 
-                builder.operatingSystem(image.getOperatingSystem());
-                String user = image.getDefaultCredentials().getUser();
-                credentialsBuilder.identity(user);
+            builder.operatingSystem(image.getOperatingSystem());
+            String user = image.getDefaultCredentials().getUser();
+            credentialsBuilder.identity(user);
+         }
+
+         builder.credentials(credentialsBuilder.build());
+
+         if (from.getServer() instanceof VServerWithVNICs) {
+
+            VServerWithVNICs server = (VServerWithVNICs) from.getServer();
+            builder.location(parseLocation(server));
+            List<String> ips = new ArrayList<String>();
+            if (server.getVnics() != null && server.getVnics().iterator().next().getPrivateIp() != null) {
+               ips.add(server.getVnics().iterator().next().getPrivateIp());
             }
+            builder.privateAddresses(ips);
+         }
+      }
+      if (from.getTemplate() != null) {
+         // when creating a new node
+         builder.location(from.getTemplate().getLocation());
+      }
 
-            builder.credentials(credentialsBuilder.build());
-
-            if (from.getServer() instanceof VServerWithVNICs) {
-
-                VServerWithVNICs server = (VServerWithVNICs) from.getServer();
-                builder.location(parseLocation(server));
-                List<String> ips = new ArrayList<String>();
-                if (server.getVnics() != null && server.getVnics().iterator().next().getPrivateIp() != null) {
-                    ips.add(server.getVnics().iterator().next().getPrivateIp());
-                }
-                builder.privateAddresses(ips);
-            }
-        }
-        if (from.getTemplate() != null) {
-            // when creating a new node
-            builder.location(from.getTemplate().getLocation());
-        }
-
-        return builder.build();
-    }
+      return builder.build();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/predicates/ServerStopped.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/predicates/ServerStopped.java
index bda281c..4c9c96b 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/predicates/ServerStopped.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/predicates/ServerStopped.java
@@ -37,27 +37,27 @@
 @Singleton
 public class ServerStopped implements Predicate<String> {
 
-    private final FGCPApi api;
+   private final FGCPApi api;
 
-    @Resource
-    protected Logger logger = Logger.NULL;
+   @Resource
+   protected Logger logger = Logger.NULL;
 
-    @Inject
-    public ServerStopped(FGCPApi api) {
-        this.api = api;
-    }
+   @Inject
+   public ServerStopped(FGCPApi api) {
+      this.api = api;
+   }
 
-    public boolean apply(String serverId) {
-        logger.trace("looking for status on server %s", serverId);
+   public boolean apply(String serverId) {
+      logger.trace("looking for status on server %s", serverId);
 
-        VServerStatus status = api.getVirtualServerApi().getStatus(serverId);
-        logger.trace("looking for status on server %s: currently: %s",
-                serverId, status);
+      VServerStatus status = api.getVirtualServerApi().getStatus(serverId);
+      logger.trace("looking for status on server %s: currently: %s",
+            serverId, status);
 
-        if (status == VServerStatus.ERROR || status == VServerStatus.STOP_ERROR)
-            throw new IllegalStateException("server not around or in error: "
-                    + status);
-        return status == VServerStatus.STOPPED;
-    }
+      if (status == VServerStatus.ERROR || status == VServerStatus.STOP_ERROR)
+         throw new IllegalStateException("server not around or in error: "
+               + status);
+      return status == VServerStatus.STOPPED;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/predicates/SystemStatusNormal.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/predicates/SystemStatusNormal.java
index 8812335..c11191e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/predicates/SystemStatusNormal.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/predicates/SystemStatusNormal.java
@@ -23,7 +23,6 @@
 import javax.inject.Singleton;
 
 import org.jclouds.fujitsu.fgcp.FGCPApi;
-import org.jclouds.fujitsu.fgcp.domain.VServerStatus;
 import org.jclouds.fujitsu.fgcp.domain.VSystemStatus;
 import org.jclouds.logging.Logger;
 
@@ -37,26 +36,26 @@
 @Singleton
 public class SystemStatusNormal implements Predicate<String> {
 
-    private final FGCPApi api;
+   private final FGCPApi api;
 
-    @Resource
-    protected Logger logger = Logger.NULL;
+   @Resource
+   protected Logger logger = Logger.NULL;
 
-    @Inject
-    public SystemStatusNormal(FGCPApi api) {
-        this.api = api;
-    }
+   @Inject
+   public SystemStatusNormal(FGCPApi api) {
+      this.api = api;
+   }
 
-    public boolean apply(String systemId) {
-        logger.trace("looking for status on system %s", systemId);
+   public boolean apply(String systemId) {
+      logger.trace("looking for status on system %s", systemId);
 
-        VSystemStatus status = api.getVirtualSystemApi().getStatus(systemId);
-        logger.trace("looking for status on system %s: currently: %s",
-                systemId, status);
+      VSystemStatus status = api.getVirtualSystemApi().getStatus(systemId);
+      logger.trace("looking for status on system %s: currently: %s",
+            systemId, status);
 
-        if (status == VSystemStatus.ERROR)
-            throw new IllegalStateException("system in error: " + status);
-        return status == VSystemStatus.NORMAL;
-    }
+      if (status == VSystemStatus.ERROR)
+         throw new IllegalStateException("system in error: " + status);
+      return status == VSystemStatus.NORMAL;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java
index 732a8a6..ef989c5 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/FGCPComputeServiceAdapter.java
@@ -44,10 +44,8 @@
 import org.jclouds.fujitsu.fgcp.compute.predicates.ServerStopped;
 import org.jclouds.fujitsu.fgcp.compute.predicates.SystemStatusNormal;
 import org.jclouds.fujitsu.fgcp.compute.strategy.VServerMetadata.Builder;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServerConfiguration;
 import org.jclouds.fujitsu.fgcp.domain.DiskImage;
 import org.jclouds.fujitsu.fgcp.domain.ServerType;
-import org.jclouds.fujitsu.fgcp.domain.VServer;
 import org.jclouds.fujitsu.fgcp.domain.VServerStatus;
 import org.jclouds.fujitsu.fgcp.domain.VServerWithDetails;
 import org.jclouds.fujitsu.fgcp.domain.VServerWithVNICs;
@@ -59,7 +57,6 @@
 import com.google.common.base.Predicate;
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -72,223 +69,223 @@
  */
 @Singleton
 public class FGCPComputeServiceAdapter implements
-        ComputeServiceAdapter<VServerMetadata, ServerType, DiskImage, Location> {
+      ComputeServiceAdapter<VServerMetadata, ServerType, DiskImage, Location> {
 
-    @Resource
-    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-    protected Logger logger = Logger.NULL;
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
 
-    private final FGCPApi api;
-    private final FGCPAsyncApi asyncApi;
-    protected Predicate<String> serverStopped = null;
-    protected Predicate<String> serverCreated = null;
-    protected Predicate<String> systemNormal = null;
-    protected ResourceIdToFirewallId toFirewallId = null;
-    protected ResourceIdToSystemId toSystemId = null;
+   private final FGCPApi api;
+   private final FGCPAsyncApi asyncApi;
+   protected Predicate<String> serverStopped = null;
+   protected Predicate<String> serverCreated = null;
+   protected Predicate<String> systemNormal = null;
+   protected ResourceIdToFirewallId toFirewallId = null;
+   protected ResourceIdToSystemId toSystemId = null;
 
-    @Inject
-    public FGCPComputeServiceAdapter(FGCPApi api, FGCPAsyncApi asyncApi,
-            ServerStopped serverStopped, SystemStatusNormal systemNormal,
-            Timeouts timeouts, ResourceIdToFirewallId toFirewallId,
-            ResourceIdToSystemId toSystemId) {
-        this.api = checkNotNull(api, "api");
-        this.asyncApi = checkNotNull(asyncApi, "asyncApi");
-        this.serverStopped = new RetryablePredicate<String>(
-                checkNotNull(serverStopped), timeouts.nodeSuspended);
-        this.serverCreated = new RetryablePredicate<String>(
-                checkNotNull(serverStopped), timeouts.nodeRunning);
-        this.systemNormal = new RetryablePredicate<String>(
-                checkNotNull(systemNormal), timeouts.nodeTerminated);
-        this.toFirewallId = checkNotNull(toFirewallId, "ResourceIdToFirewallId");
-        this.toSystemId = checkNotNull(toSystemId, "ResourceIdToSystemId");
-    }
+   @Inject
+   public FGCPComputeServiceAdapter(FGCPApi api, FGCPAsyncApi asyncApi,
+         ServerStopped serverStopped, SystemStatusNormal systemNormal,
+         Timeouts timeouts, ResourceIdToFirewallId toFirewallId,
+         ResourceIdToSystemId toSystemId) {
+      this.api = checkNotNull(api, "api");
+      this.asyncApi = checkNotNull(asyncApi, "asyncApi");
+      this.serverStopped = new RetryablePredicate<String>(
+            checkNotNull(serverStopped), timeouts.nodeSuspended);
+      this.serverCreated = new RetryablePredicate<String>(
+            checkNotNull(serverStopped), timeouts.nodeRunning);
+      this.systemNormal = new RetryablePredicate<String>(
+            checkNotNull(systemNormal), timeouts.nodeTerminated);
+      this.toFirewallId = checkNotNull(toFirewallId, "ResourceIdToFirewallId");
+      this.toSystemId = checkNotNull(toSystemId, "ResourceIdToSystemId");
+   }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public NodeAndInitialCredentials<VServerMetadata> createNodeWithGroupEncodedIntoName(
-            String group, String name, Template template) {
-        // Find vsys (how? create new? default to first found?)
-        // Target network DMZ/SECURE1/SECURE2 (how? default to DMZ?)
-        // Determine remaining params: [vserverType,diskImageId,networkId]
-        // what if no vsys exists yet? Location.AU(.contractId) creates 3? tier
-        // skeleton vsys and DMZ is picked?
-        String id = api.getVirtualSystemApi().createServer(name,
-                template.getHardware().getName(), template.getImage().getId(),
-                template.getLocation().getId());
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public NodeAndInitialCredentials<VServerMetadata> createNodeWithGroupEncodedIntoName(
+         String group, String name, Template template) {
+      // Find vsys (how? create new? default to first found?)
+      // Target network DMZ/SECURE1/SECURE2 (how? default to DMZ?)
+      // Determine remaining params: [vserverType,diskImageId,networkId]
+      // what if no vsys exists yet? Location.AU(.contractId) creates 3? tier
+      // skeleton vsys and DMZ is picked?
+      String id = api.getVirtualSystemApi().createServer(name,
+            template.getHardware().getName(), template.getImage().getId(),
+            template.getLocation().getId());
 
-        // wait until fully created (i.e. transitions to stopped status)
-        serverCreated.apply(id);
-        resumeNode(id);
-        VServerMetadata server = getNode(id);
+      // wait until fully created (i.e. transitions to stopped status)
+      serverCreated.apply(id);
+      resumeNode(id);
+      VServerMetadata server = getNode(id);
 
-        //do we need this?
-        server.setTemplate(template);
-        String user = template.getImage().getOperatingSystem().getFamily() == OsFamily.WINDOWS ? "Administrator"
-                : "root";
+      //do we need this?
+      server.setTemplate(template);
+      String user = template.getImage().getOperatingSystem().getFamily() == OsFamily.WINDOWS ? "Administrator"
+            : "root";
 
-        return new NodeAndInitialCredentials<VServerMetadata>(server,
-                id, LoginCredentials.builder().identity(user)
-                        .password(server.getInitialPassword()).build());
-    }
+      return new NodeAndInitialCredentials<VServerMetadata>(server,
+            id, LoginCredentials.builder().identity(user)
+                  .password(server.getInitialPassword()).build());
+   }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Iterable<ServerType> listHardwareProfiles() {
-        return api.getVirtualDCApi().listServerTypes();
-    }
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Iterable<ServerType> listHardwareProfiles() {
+      return api.getVirtualDCApi().listServerTypes();
+   }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Iterable<DiskImage> listImages() {
-        return api.getVirtualDCApi().listDiskImages();
-    }
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Iterable<DiskImage> listImages() {
+      return api.getVirtualDCApi().listDiskImages();
+   }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public DiskImage getImage(String id) {
-        return api.getDiskImageApi().get(id);
-    }
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public DiskImage getImage(String id) {
+      return api.getDiskImageApi().get(id);
+   }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Iterable<Location> listLocations() {
-        // Not using the adapter to determine locations
-        // see SystemAndNetworkSegmentToLocationSupplier
-        return ImmutableSet.<Location> of();
-    }
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Iterable<Location> listLocations() {
+      // Not using the adapter to determine locations
+      // see SystemAndNetworkSegmentToLocationSupplier
+      return ImmutableSet.<Location> of();
+   }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public VServerMetadata getNode(String id) {
-        Builder builder = VServerMetadata.builder();
-        builder.id(id);
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public VServerMetadata getNode(String id) {
+      Builder builder = VServerMetadata.builder();
+      builder.id(id);
 
-        List<ListenableFuture<?>> futures = new ArrayList<ListenableFuture<?>>();
+      List<ListenableFuture<?>> futures = new ArrayList<ListenableFuture<?>>();
 
-        futures.add(asyncApi.getVirtualServerApi().getDetails(id));
-        futures.add(asyncApi.getVirtualServerApi().getStatus(id));
-        futures.add(asyncApi.getVirtualServerApi().getInitialPassword(id));
-        // mapped public ips?
-        String fwId = toFirewallId.apply(id);
-//        futures.add(asyncApi.getBuiltinServerApi().getConfiguration(fwId,
-//                BuiltinServerConfiguration.SLB_RULE));
-        try {
-            List<Object> results = Futures.successfulAsList(futures).get();
-            VServerWithDetails server = (VServerWithDetails) results.get(0);
-            VServerStatus status = (VServerStatus) results.get(1);
-            System.out.println("getNode(" + id + ")'s getDetails: " + status +" - " + server);
-            if (server == null) {
-                server = api.getVirtualServerApi().getDetails(id);
-                System.out.println("getNode(" + id + ")'s getDetails(2) returns: " + server);
+      futures.add(asyncApi.getVirtualServerApi().getDetails(id));
+      futures.add(asyncApi.getVirtualServerApi().getStatus(id));
+      futures.add(asyncApi.getVirtualServerApi().getInitialPassword(id));
+      // mapped public ips?
+      String fwId = toFirewallId.apply(id);
+//      futures.add(asyncApi.getBuiltinServerApi().getConfiguration(fwId,
+//            BuiltinServerConfiguration.SLB_RULE));
+      try {
+         List<Object> results = Futures.successfulAsList(futures).get();
+         VServerWithDetails server = (VServerWithDetails) results.get(0);
+         VServerStatus status = (VServerStatus) results.get(1);
+         System.out.println("getNode(" + id + ")'s getDetails: " + status +" - " + server);
+         if (server == null) {
+            server = api.getVirtualServerApi().getDetails(id);
+            System.out.println("getNode(" + id + ")'s getDetails(2) returns: " + server);
+         }
+         builder.serverWithDetails(server);
+         builder.status(status == null ? VServerStatus.UNRECOGNIZED : status);
+//         System.out.println("status in adapter#getNode: " 
+//         + (VServerStatus) results.get(1) 
+//         +" for " 
+//         + server.getId());
+         builder.initialPassword((String) results.get(2));
+//         SLB slb = ((BuiltinServer) results.get(4)).;
+//         slb.
+      } catch (InterruptedException e) {
+         throw Throwables.propagate(e);
+      } catch (ExecutionException e) {
+         throw Throwables.propagate(e);
+      }
+      return builder.build();
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public Iterable<VServerMetadata> listNodes() {
+      ImmutableSet.Builder<VServerMetadata> servers = ImmutableSet
+            .<VServerMetadata> builder();
+
+      Set<VSystem> systems = api.getVirtualDCApi().listVirtualSystems();
+      List<ListenableFuture<VSystemWithDetails>> futures = new ArrayList<ListenableFuture<VSystemWithDetails>>();
+      for (VSystem system : systems) {
+
+         futures.add(asyncApi.getVirtualSystemApi().getDetails(
+               system.getId()));
+      }
+      try {
+         for (VSystemWithDetails system : Futures.successfulAsList(futures)
+               .get()) {
+
+            if (system != null) {
+
+               for (VServerWithVNICs server : system.getServers()) {
+
+                  // skip FW (S-0001) and SLBs (>0 for SLB)
+                  if (!server.getId().endsWith("-S-0001") && server.getVnics().iterator().next().getNicNo() == 0) {
+
+                     servers.add(getNode(server.getId()));
+//                    Builder builder = VServerMetadata.builder();
+//                    builder.server(server);
+//                    builder.status(VServerStatus.UNRECOGNIZED);
+//                    servers.add(builder.build());
+                  }
+               }
             }
-            builder.serverWithDetails(server);
-            builder.status(status == null ? VServerStatus.UNRECOGNIZED : status);
-//            System.out.println("status in adapter#getNode: " 
-//            + (VServerStatus) results.get(1) 
-//            +" for " 
-//            + server.getId());
-            builder.initialPassword((String) results.get(2));
-//            SLB slb = ((BuiltinServer) results.get(4)).;
-//            slb.
-        } catch (InterruptedException e) {
-            throw Throwables.propagate(e);
-        } catch (ExecutionException e) {
-            throw Throwables.propagate(e);
-        }
-        return builder.build();
-    }
+         }
+      } catch (InterruptedException e) {
+         throw Throwables.propagate(e);
+      } catch (ExecutionException e) {
+         throw Throwables.propagate(e);
+      }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Iterable<VServerMetadata> listNodes() {
-        ImmutableSet.Builder<VServerMetadata> servers = ImmutableSet
-                .<VServerMetadata> builder();
+      return servers.build();
+   }
 
-        Set<VSystem> systems = api.getVirtualDCApi().listVirtualSystems();
-        List<ListenableFuture<VSystemWithDetails>> futures = new ArrayList<ListenableFuture<VSystemWithDetails>>();
-        for (VSystem system : systems) {
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public void destroyNode(String id) {
+      api.getVirtualServerApi().destroy(id);
+      // wait until fully destroyed
+      String systemId = toSystemId.apply(id);
+      systemNormal.apply(systemId);
+   }
 
-            futures.add(asyncApi.getVirtualSystemApi().getDetails(
-                    system.getId()));
-        }
-        try {
-            for (VSystemWithDetails system : Futures.successfulAsList(futures)
-                    .get()) {
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public void rebootNode(String id) {
+      suspendNode(id);
+      // wait until fully stopped
+      serverStopped.apply(id);
+      resumeNode(id);
+   }
 
-                if (system != null) {
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public void resumeNode(String id) {
+      api.getVirtualServerApi().start(id);
+   }
 
-                    for (VServerWithVNICs server : system.getServers()) {
-
-                        // skip FW (S-0001) and SLBs (>0 for SLB)
-                        if (!server.getId().endsWith("-S-0001") && server.getVnics().iterator().next().getNicNo() == 0) {
-
-                            servers.add(getNode(server.getId()));
-//                          Builder builder = VServerMetadata.builder();
-//                          builder.server(server);
-//                          builder.status(VServerStatus.UNRECOGNIZED);
-//                          servers.add(builder.build());
-                        }
-                    }
-                }
-            }
-        } catch (InterruptedException e) {
-            throw Throwables.propagate(e);
-        } catch (ExecutionException e) {
-            throw Throwables.propagate(e);
-        }
-
-        return servers.build();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void destroyNode(String id) {
-        api.getVirtualServerApi().destroy(id);
-        // wait until fully destroyed
-        String systemId = toSystemId.apply(id);
-        systemNormal.apply(systemId);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void rebootNode(String id) {
-        suspendNode(id);
-        // wait until fully stopped
-        serverStopped.apply(id);
-        resumeNode(id);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void resumeNode(String id) {
-        api.getVirtualServerApi().start(id);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void suspendNode(String id) {
-        api.getVirtualServerApi().stop(id);
-    }
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public void suspendNode(String id) {
+      api.getVirtualServerApi().stop(id);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/VServerMetadata.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/VServerMetadata.java
index e9835ac..d0eb0a1 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/VServerMetadata.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/compute/strategy/VServerMetadata.java
@@ -39,140 +39,140 @@
  */
 public class VServerMetadata {
 
-    protected VServer server;
-    protected String id;
-    protected String name;
-    protected Template template;
-    protected String initialPassword;
-    protected VServerStatus status = VServerStatus.UNRECOGNIZED;
-    protected Set<PublicIP> ips;
-    protected DiskImage image;
+   protected VServer server;
+   protected String id;
+   protected String name;
+   protected Template template;
+   protected String initialPassword;
+   protected VServerStatus status = VServerStatus.UNRECOGNIZED;
+   protected Set<PublicIP> ips;
+   protected DiskImage image;
 
-    public VServerMetadata(VServer server, String initialPassword,
-            VServerStatus status, DiskImage image, Set<PublicIP> publicIps) {
-        this.server = checkNotNull(server, "server");
-        this.initialPassword = initialPassword;
-        this.status = status;
-        this.image = image;
-        this.ips = publicIps;
-        id = server.getId();
-        name = server.getName();
-    }
+   public VServerMetadata(VServer server, String initialPassword,
+         VServerStatus status, DiskImage image, Set<PublicIP> publicIps) {
+      this.server = checkNotNull(server, "server");
+      this.initialPassword = initialPassword;
+      this.status = status;
+      this.image = image;
+      this.ips = publicIps;
+      id = server.getId();
+      name = server.getName();
+   }
 
-    public VServerMetadata(String id, String name, Template template,
-            VServerStatus status) {
-        this.id = checkNotNull(id, "id");
-        this.name = checkNotNull(name, "name");
-        this.template = checkNotNull(template, "template");
-        this.status = checkNotNull(status, "status");
-    }
+   public VServerMetadata(String id, String name, Template template,
+         VServerStatus status) {
+      this.id = checkNotNull(id, "id");
+      this.name = checkNotNull(name, "name");
+      this.template = checkNotNull(template, "template");
+      this.status = checkNotNull(status, "status");
+   }
 
-    public VServer getServer() {
-        return server;
-    }
+   public VServer getServer() {
+      return server;
+   }
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public String getName() {
-        return name;
-    }
+   public String getName() {
+      return name;
+   }
 
-    public Template getTemplate() {
-        return template;
-    }
+   public Template getTemplate() {
+      return template;
+   }
 
-    public void setTemplate(Template template) {
-        this.template = template;
-    }
+   public void setTemplate(Template template) {
+      this.template = template;
+   }
 
-    public String getInitialPassword() {
-        return initialPassword;
-    }
+   public String getInitialPassword() {
+      return initialPassword;
+   }
 
-    public VServerStatus getStatus() {
-        return status;
-    }
+   public VServerStatus getStatus() {
+      return status;
+   }
 
-    public Set<PublicIP> getIps() {
-        return ips;
-    }
+   public Set<PublicIP> getIps() {
+      return ips;
+   }
 
-    public static Builder builder() {
-        return new Builder();
-    }
+   public static Builder builder() {
+      return new Builder();
+   }
 
-    public static class Builder {
-        private VServer server;
-        private VServerWithVNICs serverWithDetails;
-        private String id;
-        private String name;
-        private Template template;
-        private String initialPassword;
-        private VServerStatus status = VServerStatus.UNRECOGNIZED;
-        private Set<PublicIP> publicIps = ImmutableSet.of();
-        private DiskImage image;
+   public static class Builder {
+      private VServer server;
+      private VServerWithVNICs serverWithDetails;
+      private String id;
+      private String name;
+      private Template template;
+      private String initialPassword;
+      private VServerStatus status = VServerStatus.UNRECOGNIZED;
+      private Set<PublicIP> publicIps = ImmutableSet.of();
+      private DiskImage image;
 
-        public Builder id(String id) {
-            this.id = id;
-            return this;
-        }
+      public Builder id(String id) {
+         this.id = id;
+         return this;
+      }
 
-        public Builder name(String name) {
-            this.name = name;
-            return this;
-        }
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
 
-        public Builder template(Template template) {
-            this.template = template;
-            return this;
-        }
+      public Builder template(Template template) {
+         this.template = template;
+         return this;
+      }
 
-//        public Builder server(VServer server) {
-//            this.server = server;
-//            return this;
-//        }
+//      public Builder server(VServer server) {
+//         this.server = server;
+//         return this;
+//      }
 
-        public Builder serverWithDetails(VServerWithVNICs serverWithDetails) {
-            this.serverWithDetails = serverWithDetails;
-            return this;
-        }
+      public Builder serverWithDetails(VServerWithVNICs serverWithDetails) {
+         this.serverWithDetails = serverWithDetails;
+         return this;
+      }
 
-        public Builder initialPassword(String password) {
-            this.initialPassword = password;
-            return this;
-        }
+      public Builder initialPassword(String password) {
+         this.initialPassword = password;
+         return this;
+      }
 
-        public Builder status(VServerStatus status) {
-            this.status = status;
-            return this;
-        }
+      public Builder status(VServerStatus status) {
+         this.status = status;
+         return this;
+      }
 
-        public Builder image(DiskImage image) {
-            this.image = image;
-            return this;
-        }
+      public Builder image(DiskImage image) {
+         this.image = image;
+         return this;
+      }
 
-        public Builder publicIps(Set<PublicIP> publicIps) {
-            this.publicIps = publicIps;
-            return this;
-        }
+      public Builder publicIps(Set<PublicIP> publicIps) {
+         this.publicIps = publicIps;
+         return this;
+      }
 
-        public VServerMetadata build() {
-            if (initialPassword == null) initialPassword = "";
-            if (server != null) {
-                return new VServerMetadata(server, initialPassword, status,
-                        image, publicIps);
-            } else if (serverWithDetails != null) {
-                return new VServerMetadata(serverWithDetails, initialPassword,
-                        status, image, publicIps);
-            } else {
-                // sometimes these fields are null because the server is returning a verify error
-                if (id == null) id = "dummy-id";
-                if (name == null) name = "dummy-name";
-                return new VServerMetadata(id, name, template, status);
-            }
-        }
-    }
+      public VServerMetadata build() {
+         if (initialPassword == null) initialPassword = "";
+         if (server != null) {
+            return new VServerMetadata(server, initialPassword, status,
+                  image, publicIps);
+         } else if (serverWithDetails != null) {
+            return new VServerMetadata(serverWithDetails, initialPassword,
+                  status, image, publicIps);
+         } else {
+            // sometimes these fields are null because the server is returning a verify error
+            if (id == null) id = "dummy-id";
+            if (name == null) name = "dummy-name";
+            return new VServerMetadata(id, name, template, status);
+         }
+      }
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/AddressRange.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/AddressRange.java
index 032a718..30755a9 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/AddressRange.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/AddressRange.java
@@ -28,30 +28,30 @@
  */
 @XmlRootElement(name = "addressrange")
 public class AddressRange {
-    private String range;
+   private String range;
 
-    private String from;
+   private String from;
 
-    private String to;
+   private String to;
 
-    /**
-     * @return the range
-     */
-    public String getRange() {
-        return range;
-    }
+   /**
+    * @return the range
+    */
+   public String getRange() {
+      return range;
+   }
 
-    /**
-     * @return the from
-     */
-    public String getFrom() {
-        return from;
-    }
+   /**
+    * @return the from
+    */
+   public String getFrom() {
+      return from;
+   }
 
-    /**
-     * @return the to
-     */
-    public String getTo() {
-        return to;
-    }
+   /**
+    * @return the to
+    */
+   public String getTo() {
+      return to;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServer.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServer.java
index 911b05c..cd83251 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServer.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServer.java
@@ -29,45 +29,45 @@
  */
 @XmlRootElement(name = "efm")
 public class BuiltinServer {
-    @XmlElement(name = "efmId")
-    private String id;
-    @XmlElement(name = "efmType")
-    private BuiltinServerType builtinServerType;
-    @XmlElement(name = "efmName")
-    private String name;
-    private String creator;
-    private String slbVip;
-    private Firewall firewall;
-    private SLB loadbalancer;
+   @XmlElement(name = "efmId")
+   private String id;
+   @XmlElement(name = "efmType")
+   private BuiltinServerType builtinServerType;
+   @XmlElement(name = "efmName")
+   private String name;
+   private String creator;
+   private String slbVip;
+   private Firewall firewall;
+   private SLB loadbalancer;
 
-    public enum BuiltinServerType {FW, SLB}
+   public enum BuiltinServerType {FW, SLB}
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public BuiltinServerType getType() {
-        return builtinServerType;
-    }
+   public BuiltinServerType getType() {
+      return builtinServerType;
+   }
 
-    public String getName() {
-        return name;
-    }
+   public String getName() {
+      return name;
+   }
 
-    public String getCreator() {
-        return creator;
-    }
+   public String getCreator() {
+      return creator;
+   }
 
-    public String getSlbVip() {
-        return slbVip;
-    }
+   public String getSlbVip() {
+      return slbVip;
+   }
 
-    public Firewall getFirewall() {
-        return firewall;
-    }
+   public Firewall getFirewall() {
+      return firewall;
+   }
 
-    public SLB getLoadbalancer() {
-        return loadbalancer;
-    }
+   public SLB getLoadbalancer() {
+      return loadbalancer;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerBackup.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerBackup.java
index 79374f9..8548758 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerBackup.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerBackup.java
@@ -31,45 +31,45 @@
  */
 @XmlRootElement(name = "backup")
 public class BuiltinServerBackup {
-    @XmlElement(name = "backupId")
-    private String id;
-    @XmlElement(name = "backupTime")
-    private String time;
+   @XmlElement(name = "backupId")
+   private String id;
+   @XmlElement(name = "backupTime")
+   private String time;
 
-    /**
-     * @return the id
-     */
-    public String getId() {
-        return id;
-    }
+   /**
+    * @return the id
+    */
+   public String getId() {
+      return id;
+   }
 
-    /**
-     * @return the time
-     */
-    public String getTime() {
-        return time;
-    }
+   /**
+    * @return the time
+    */
+   public String getTime() {
+      return time;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        BuiltinServerBackup that = BuiltinServerBackup.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      BuiltinServerBackup that = BuiltinServerBackup.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("time", time).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("time", time).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerConfiguration.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerConfiguration.java
index 5f7fa6a..1225446 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerConfiguration.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerConfiguration.java
@@ -33,36 +33,36 @@
  * @author Dies Koper
  */
 public enum BuiltinServerConfiguration {
-    FW_NAT_RULE,
-    FW_DNS,
-    FW_POLICY,
-    FW_LOG,
-    FW_LIMIT_POLICY,
-    SLB_RULE,
-    SLB_LOAD_STATISTICS,
-    SLB_ERROR_STATISTICS,
-    SLB_CERTIFICATE_LIST,
-    EFM_UPDATE,
-    SLB_CONNECTION,
-    UNRECOGNIZED;
+   FW_NAT_RULE,
+   FW_DNS,
+   FW_POLICY,
+   FW_LOG,
+   FW_LIMIT_POLICY,
+   SLB_RULE,
+   SLB_LOAD_STATISTICS,
+   SLB_ERROR_STATISTICS,
+   SLB_CERTIFICATE_LIST,
+   EFM_UPDATE,
+   SLB_CONNECTION,
+   UNRECOGNIZED;
 
-    public String value() {
-        return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
-    }
+   public String value() {
+      return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
+   }
 
-    @Override
-    public String toString() {
-        return value();
-    }
+   @Override
+   public String toString() {
+      return value();
+   }
 
-    public static BuiltinServerConfiguration fromValue(String configuration) {
-        try {
-            return valueOf(CaseFormat.UPPER_CAMEL
-                    .to(CaseFormat.UPPER_UNDERSCORE,
-                            checkNotNull(configuration, "configuration")));
-        } catch (IllegalArgumentException e) {
-            return UNRECOGNIZED;
-        }
-    }
+   public static BuiltinServerConfiguration fromValue(String configuration) {
+      try {
+         return valueOf(CaseFormat.UPPER_CAMEL
+               .to(CaseFormat.UPPER_UNDERSCORE,
+                     checkNotNull(configuration, "configuration")));
+      } catch (IllegalArgumentException e) {
+         return UNRECOGNIZED;
+      }
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerStatus.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerStatus.java
index 4ee7ba2..9df85d3 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerStatus.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/BuiltinServerStatus.java
@@ -18,12 +18,12 @@
  */
 package org.jclouds.fujitsu.fgcp.domain;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import javax.xml.bind.annotation.XmlRootElement;
 
 import com.google.common.base.CaseFormat;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 /**
  * Possible statuses of a built-in server, also called extended function module
  * (EFM), such as a firewall or load balancer (SLB).
@@ -36,25 +36,25 @@
  */
 @XmlRootElement(name = "efmStatus")
 public enum BuiltinServerStatus {
-    DEPLOYING, RUNNING, STOPPING, STOPPED, STARTING, FAILOVER, UNEXPECTED_STOP, RESTORING, BACKUP_ING, ERROR, EXECUTE_NETWORK_SERVER, START_ERROR, STOP_ERROR, UPDATE, BACKOUT, UNRECOGNIZED;
+   DEPLOYING, RUNNING, STOPPING, STOPPED, STARTING, FAILOVER, UNEXPECTED_STOP, RESTORING, BACKUP_ING, ERROR, EXECUTE_NETWORK_SERVER, START_ERROR, STOP_ERROR, UPDATE, BACKOUT, UNRECOGNIZED;
 
-    public String value() {
-        return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
-    }
+   public String value() {
+      return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
+   }
 
-    @Override
-    public String toString() {
-        return value();
-    }
+   @Override
+   public String toString() {
+      return value();
+   }
 
-    public static BuiltinServerStatus fromValue(String status) {
-        try {
-            return valueOf(CaseFormat.UPPER_CAMEL
-                    .to(CaseFormat.UPPER_UNDERSCORE,
-                            checkNotNull(status, "status")));
-        } catch (IllegalArgumentException e) {
-            return UNRECOGNIZED;
-        }
-    }
+   public static BuiltinServerStatus fromValue(String status) {
+      try {
+         return valueOf(CaseFormat.UPPER_CAMEL
+               .to(CaseFormat.UPPER_UNDERSCORE,
+                     checkNotNull(status, "status")));
+      } catch (IllegalArgumentException e) {
+         return UNRECOGNIZED;
+      }
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/CPU.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/CPU.java
index b49b9e8..f7fa487 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/CPU.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/CPU.java
@@ -30,48 +30,48 @@
  */
 @XmlRootElement(name = "cpu")
 public class CPU {
-    @XmlElement(name = "cpuArch")
-    private String arch;
-    @XmlElement(name = "cpuPerf")
-    private double speedPerCore;
-    @XmlElement(name = "numOfCpu")
-    private double cores;
+   @XmlElement(name = "cpuArch")
+   private String arch;
+   @XmlElement(name = "cpuPerf")
+   private double speedPerCore;
+   @XmlElement(name = "numOfCpu")
+   private double cores;
 
-    public String getArch() {
-        return arch;
-    }
+   public String getArch() {
+      return arch;
+   }
 
-    public double getSpeedPerCore() {
-        return speedPerCore;
-    }
+   public double getSpeedPerCore() {
+      return speedPerCore;
+   }
 
-    public double getCores() {
-        return cores;
-    }
+   public double getCores() {
+      return cores;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(cores, speedPerCore, arch);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(cores, speedPerCore, arch);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        CPU that = CPU.class.cast(obj);
-        return Objects.equal(this.cores, that.cores)
-                && Objects.equal(this.speedPerCore, that.speedPerCore)
-                && Objects.equal(this.arch, that.arch);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      CPU that = CPU.class.cast(obj);
+      return Objects.equal(this.cores, that.cores)
+            && Objects.equal(this.speedPerCore, that.speedPerCore)
+            && Objects.equal(this.arch, that.arch);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("cores", cores).add("speedPerCore", speedPerCore)
-                .add("arch", arch).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("cores", cores).add("speedPerCore", speedPerCore)
+            .add("arch", arch).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Cause.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Cause.java
index c2863db..3e13e10 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Cause.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Cause.java
@@ -25,76 +25,76 @@
  * @author Dies Koper
  */
 public class Cause {
-    private String cat;
+   private String cat;
 
-    private String status;
+   private String status;
 
-    private String filePath;
+   private String filePath;
 
-    private String current;
+   private String current;
 
-    private String before;
+   private String before;
 
-    private String today;
+   private String today;
 
-    private String yesterday;
+   private String yesterday;
 
-    private String total;
+   private String total;
 
-    /**
-     * @return category
-     */
-    public String getCat() {
-        return cat;
-    }
+   /**
+    * @return category
+    */
+   public String getCat() {
+      return cat;
+   }
 
-    /**
-     * @return the status
-     */
-    public String getStatus() {
-        return status;
-    }
+   /**
+    * @return the status
+    */
+   public String getStatus() {
+      return status;
+   }
 
-    /**
-     * @return the filePath
-     */
-    public String getFilePath() {
-        return filePath;
-    }
+   /**
+    * @return the filePath
+    */
+   public String getFilePath() {
+      return filePath;
+   }
 
-    /**
-     * @return the current
-     */
-    public String getCurrent() {
-        return current;
-    }
+   /**
+    * @return the current
+    */
+   public String getCurrent() {
+      return current;
+   }
 
-    /**
-     * @return the before
-     */
-    public String getBefore() {
-        return before;
-    }
+   /**
+    * @return the before
+    */
+   public String getBefore() {
+      return before;
+   }
 
-    /**
-     * @return the today
-     */
-    public String getToday() {
-        return today;
-    }
+   /**
+    * @return the today
+    */
+   public String getToday() {
+      return today;
+   }
 
-    /**
-     * @return the yesterday
-     */
-    public String getYesterday() {
-        return yesterday;
-    }
+   /**
+    * @return the yesterday
+    */
+   public String getYesterday() {
+      return yesterday;
+   }
 
-    /**
-     * @return the total
-     */
-    public String getTotal() {
-        return total;
-    }
+   /**
+    * @return the total
+    */
+   public String getTotal() {
+      return total;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Direction.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Direction.java
index b332fdc..b76ad1d 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Direction.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Direction.java
@@ -32,82 +32,82 @@
  * @author Dies Koper
  */
 public class Direction {
-    private String from;
-    private String to;
-    private Set<Policy> policies = new LinkedHashSet<Policy>();
-    private Acceptable acceptable;
-    private Prefix prefix;
-    private int maxPolicyNum;
+   private String from;
+   private String to;
+   private Set<Policy> policies = new LinkedHashSet<Policy>();
+   private Acceptable acceptable;
+   private Prefix prefix;
+   private int maxPolicyNum;
 
-    enum Acceptable {OK, NG}
-    enum Prefix {free, src, dst, proto, srcport, dstport, action, rule, tab}
+   enum Acceptable {OK, NG}
+   enum Prefix {free, src, dst, proto, srcport, dstport, action, rule, tab}
 
-    /**
-     * @return the from
-     */
-    public String getFrom() {
-        return from;
-    }
+   /**
+    * @return the from
+    */
+   public String getFrom() {
+      return from;
+   }
 
-    /**
-     * @return the to
-     */
-    public String getTo() {
-        return to;
-    }
+   /**
+    * @return the to
+    */
+   public String getTo() {
+      return to;
+   }
 
-    /**
-     * @return the policies
-     */
-    public Set<Policy> getPolicies() {
-        return policies == null ? ImmutableSet.<Policy> of() : ImmutableSet
-                .copyOf(policies);
-    }
+   /**
+    * @return the policies
+    */
+   public Set<Policy> getPolicies() {
+      return policies == null ? ImmutableSet.<Policy> of() : ImmutableSet
+            .copyOf(policies);
+   }
 
-    /**
-     * @return the acceptable
-     */
-    public Acceptable getAcceptable() {
-        return acceptable;
-    }
+   /**
+    * @return the acceptable
+    */
+   public Acceptable getAcceptable() {
+      return acceptable;
+   }
 
-    /**
-     * @return the prefix
-     */
-    public Prefix getPrefix() {
-        return prefix;
-    }
+   /**
+    * @return the prefix
+    */
+   public Prefix getPrefix() {
+      return prefix;
+   }
 
-    /**
-     * @return the maxPolicyNum
-     */
-    public int getMaxPolicyNum() {
-        return maxPolicyNum;
-    }
+   /**
+    * @return the maxPolicyNum
+    */
+   public int getMaxPolicyNum() {
+      return maxPolicyNum;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(from, to);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(from, to);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Direction that = Direction.class.cast(obj);
-        return Objects.equal(this.from, that.from)
-                && Objects.equal(this.to, that.to);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Direction that = Direction.class.cast(obj);
+      return Objects.equal(this.from, that.from)
+            && Objects.equal(this.to, that.to);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("from", from)
-                .add("to", to).add("prefix", prefix).add("policies", policies)
-                .add("maxPolicyNum", maxPolicyNum)
-                .add("acceptable", acceptable).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("from", from)
+            .add("to", to).add("prefix", prefix).add("policies", policies)
+            .add("maxPolicyNum", maxPolicyNum)
+            .add("acceptable", acceptable).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Disk.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Disk.java
index dae088f..cae3da8 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Disk.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Disk.java
@@ -29,57 +29,57 @@
  */
 @XmlRootElement
 public class Disk {
-    @XmlElement(name = "diskSize")
-    private String size;
+   @XmlElement(name = "diskSize")
+   private String size;
 
-    @XmlElement(name = "diskUsage")
-    private String usage;
+   @XmlElement(name = "diskUsage")
+   private String usage;
 
-    @XmlElement(name = "diskType")
-    private String type;
+   @XmlElement(name = "diskType")
+   private String type;
 
-    public String getSize() {
-        return size;
-    }
+   public String getSize() {
+      return size;
+   }
 
-    public String getUsage() {
-        return usage;
-    }
+   public String getUsage() {
+      return usage;
+   }
 
-    public String getType() {
-        return type;
-    }
+   public String getType() {
+      return type;
+   }
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (!(o instanceof Disk))
-            return false;
+   @Override
+   public boolean equals(Object o) {
+      if (this == o)
+         return true;
+      if (!(o instanceof Disk))
+         return false;
 
-        Disk disk = (Disk) o;
+      Disk disk = (Disk) o;
 
-        if (size != null ? !size.equals(disk.size) : disk.size != null)
-            return false;
-        if (type != null ? !type.equals(disk.type) : disk.type != null)
-            return false;
-        if (usage != null ? !usage.equals(disk.usage) : disk.usage != null)
-            return false;
+      if (size != null ? !size.equals(disk.size) : disk.size != null)
+         return false;
+      if (type != null ? !type.equals(disk.type) : disk.type != null)
+         return false;
+      if (usage != null ? !usage.equals(disk.usage) : disk.usage != null)
+         return false;
 
-        return true;
-    }
+      return true;
+   }
 
-    @Override
-    public int hashCode() {
-        int result = size != null ? size.hashCode() : 0;
-        result = 31 * result + (usage != null ? usage.hashCode() : 0);
-        result = 31 * result + (type != null ? type.hashCode() : 0);
-        return result;
-    }
+   @Override
+   public int hashCode() {
+      int result = size != null ? size.hashCode() : 0;
+      result = 31 * result + (usage != null ? usage.hashCode() : 0);
+      result = 31 * result + (type != null ? type.hashCode() : 0);
+      return result;
+   }
 
-    @Override
-    public String toString() {
-        return "Disk{" + "size='" + size + '\'' + ", usage='" + usage + '\''
-                + ", type='" + type + '\'' + '}';
-    }
+   @Override
+   public String toString() {
+      return "Disk{" + "size='" + size + '\'' + ", usage='" + usage + '\''
+            + ", type='" + type + '\'' + '}';
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/DiskImage.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/DiskImage.java
index 5e2d3e1..6540f35 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/DiskImage.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/DiskImage.java
@@ -37,164 +37,164 @@
  */
 @XmlRootElement(name = "diskimage")
 public class DiskImage {
-    @XmlElement(name = "diskimageId")
-    private String id;
+   @XmlElement(name = "diskimageId")
+   private String id;
 
-    @XmlElement(name = "diskimageName")
-    private String name;
+   @XmlElement(name = "diskimageName")
+   private String name;
 
-    private int size;
+   private int size;
 
-    private String osName;
+   private String osName;
 
-    private String osType;
+   private String osType;
 
-    private String creatorName;
+   private String creatorName;
 
-    private String registrant;
+   private String registrant;
 
-    private String licenseInfo;
+   private String licenseInfo;
 
-    private String description;
+   private String description;
 
-    @XmlElementWrapper(name = "softwares")
-    @XmlElement(name = "software")
-    private Set<Software> software = new LinkedHashSet<Software>();
+   @XmlElementWrapper(name = "softwares")
+   @XmlElement(name = "software")
+   private Set<Software> software = new LinkedHashSet<Software>();
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public int getSize() {
-        return size;
-    }
+   public int getSize() {
+      return size;
+   }
 
-    public String getOsName() {
-        return osName;
-    }
+   public String getOsName() {
+      return osName;
+   }
 
-    public String getOsType() {
-        return osType;
-    }
+   public String getOsType() {
+      return osType;
+   }
 
-    public String getCreatorName() {
-        return creatorName;
-    }
+   public String getCreatorName() {
+      return creatorName;
+   }
 
-    public String getRegistrant() {
-        return registrant;
-    }
+   public String getRegistrant() {
+      return registrant;
+   }
 
-    public String getLicenseInfo() {
-        return licenseInfo;
-    }
+   public String getLicenseInfo() {
+      return licenseInfo;
+   }
 
-    public String getDescription() {
-        return description;
-    }
+   public String getDescription() {
+      return description;
+   }
 
-    public String getName() {
-        return name;
-    }
+   public String getName() {
+      return name;
+   }
 
-    public Set<Software> getSoftware() {
-        return software == null ? ImmutableSet.<Software> of() : ImmutableSet
-                .copyOf(software);
-    }
+   public Set<Software> getSoftware() {
+      return software == null ? ImmutableSet.<Software> of() : ImmutableSet
+            .copyOf(software);
+   }
 
-    public static Builder builder() {
-        return new Builder();
-    }
+   public static Builder builder() {
+      return new Builder();
+   }
 
-    public static class Builder {
-        private String id;
-        private String name;
-        private int size;
-        private String osName;
-        private String osType;
-        private String creatorName;
-        private String registrant;
-        private String licenseInfo;
-        private String description;
-        private Set<Software> software;
+   public static class Builder {
+      private String id;
+      private String name;
+      private int size;
+      private String osName;
+      private String osType;
+      private String creatorName;
+      private String registrant;
+      private String licenseInfo;
+      private String description;
+      private Set<Software> software;
 
-        public Builder id(String id) {
-            this.id = id;
-            return this;
-        }
+      public Builder id(String id) {
+         this.id = id;
+         return this;
+      }
 
-        public Builder name(String name) {
-            this.name = name;
-            return this;
-        }
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
 
-        public Builder osName(String osName) {
-            this.osName = osName;
-            return this;
-        }
+      public Builder osName(String osName) {
+         this.osName = osName;
+         return this;
+      }
 
-        public Builder osType(String osType) {
-            this.osType = osType;
-            return this;
-        }
+      public Builder osType(String osType) {
+         this.osType = osType;
+         return this;
+      }
 
-        public Builder creatorName(String creatorName) {
-            this.creatorName = creatorName;
-            return this;
-        }
+      public Builder creatorName(String creatorName) {
+         this.creatorName = creatorName;
+         return this;
+      }
 
-        public Builder registrant(String registrant) {
-            this.registrant = registrant;
-            return this;
-        }
+      public Builder registrant(String registrant) {
+         this.registrant = registrant;
+         return this;
+      }
 
-        public Builder description(String description) {
-            this.description = description;
-            return this;
-        }
+      public Builder description(String description) {
+         this.description = description;
+         return this;
+      }
 
-        public DiskImage build() {
-            DiskImage image = new DiskImage();
+      public DiskImage build() {
+         DiskImage image = new DiskImage();
 
-            image.id = id;
-            image.name = name;
-            image.size = size;
-            image.osName = osName;
-            image.osType = osType;
-            image.creatorName = creatorName;
-            image.registrant = registrant;
-            image.licenseInfo = licenseInfo;
-            image.description = description;
-            image.software = software;
+         image.id = id;
+         image.name = name;
+         image.size = size;
+         image.osName = osName;
+         image.osType = osType;
+         image.creatorName = creatorName;
+         image.registrant = registrant;
+         image.licenseInfo = licenseInfo;
+         image.description = description;
+         image.software = software;
 
-            return image;
-        }
-    }
+         return image;
+      }
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        DiskImage that = DiskImage.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      DiskImage that = DiskImage.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("osName", osName).add("osType", osType)
-                .add("size", size).add("creatorName", creatorName)
-                .add("description", description)
-                .add("licenseInfo", licenseInfo).add("registrant", registrant)
-                .add("software", software).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("osName", osName).add("osType", osType)
+            .add("size", size).add("creatorName", creatorName)
+            .add("description", description)
+            .add("licenseInfo", licenseInfo).add("registrant", registrant)
+            .add("software", software).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ErrorStatistics.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ErrorStatistics.java
index 28cb1e7..d576409 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ErrorStatistics.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ErrorStatistics.java
@@ -32,22 +32,22 @@
  */
 @XmlRootElement(name = "errorstatistics")
 public class ErrorStatistics {
-    private Period period;
-    private Set<Group> groups = new LinkedHashSet<Group>();
+   private Period period;
+   private Set<Group> groups = new LinkedHashSet<Group>();
 
-    /**
-     * @return the period
-     */
-    public Period getPeriod() {
-        return period;
-    }
+   /**
+    * @return the period
+    */
+   public Period getPeriod() {
+      return period;
+   }
 
-    /**
-     * @return the groups
-     */
-    public Set<Group> getGroups() {
-        return groups == null ? ImmutableSet.<Group> of() : ImmutableSet
-                .copyOf(groups);
-    }
+   /**
+    * @return the groups
+    */
+   public Set<Group> getGroups() {
+      return groups == null ? ImmutableSet.<Group> of() : ImmutableSet
+            .copyOf(groups);
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/EventLog.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/EventLog.java
index bda7e23..f9eef69 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/EventLog.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/EventLog.java
@@ -29,71 +29,71 @@
  */
 @XmlRootElement(name = "errorlog")
 public class EventLog {
-    private String title;
-    private String message;
-    private String startDate;
-    private String expiry;
-    private String entryDate;
+   private String title;
+   private String message;
+   private String startDate;
+   private String expiry;
+   private String entryDate;
 
-    /**
-     * @return the title
-     */
-    public String getTitle() {
-        return title;
-    }
+   /**
+    * @return the title
+    */
+   public String getTitle() {
+      return title;
+   }
 
-    /**
-     * @return the message
-     */
-    public String getMessage() {
-        return message;
-    }
+   /**
+    * @return the message
+    */
+   public String getMessage() {
+      return message;
+   }
 
-    /**
-     * @return the startDate
-     */
-    public String getStartDate() {
-        return startDate;
-    }
+   /**
+    * @return the startDate
+    */
+   public String getStartDate() {
+      return startDate;
+   }
 
-    /**
-     * @return the expiry
-     */
-    public String getExpiry() {
-        return expiry;
-    }
+   /**
+    * @return the expiry
+    */
+   public String getExpiry() {
+      return expiry;
+   }
 
-    /**
-     * @return the entryDate
-     */
-    public String getEntryDate() {
-        return entryDate;
-    }
+   /**
+    * @return the entryDate
+    */
+   public String getEntryDate() {
+      return entryDate;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(entryDate, message, title);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(entryDate, message, title);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        EventLog that = EventLog.class.cast(obj);
-        return Objects.equal(this.entryDate, that.entryDate)
-                && Objects.equal(this.message, that.message)
-                && Objects.equal(this.title, that.title);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      EventLog that = EventLog.class.cast(obj);
+      return Objects.equal(this.entryDate, that.entryDate)
+            && Objects.equal(this.message, that.message)
+            && Objects.equal(this.title, that.title);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("entryDate", entryDate).add("title", title)
-                .add("message", message).add("startDate", startDate)
-                .add("expiry", expiry).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("entryDate", entryDate).add("title", title)
+            .add("message", message).add("startDate", startDate)
+            .add("expiry", expiry).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Firewall.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Firewall.java
index f466c05..26f1c7e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Firewall.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Firewall.java
@@ -32,102 +32,102 @@
  */
 @XmlRootElement(name = "fw")
 public class Firewall {
-    private NAT nat;
-    private Set<Direction> directions = new LinkedHashSet<Direction>();
-    private String log;
-    private String status;
-    private String category;
-    private String latestVersion;
-    private String comment;
-    private boolean firmUpdateExist;
-    private boolean configUpdateExist;
-    private String backout;
-    private String updateDate;
-    private String currentVersion;
+   private NAT nat;
+   private Set<Direction> directions = new LinkedHashSet<Direction>();
+   private String log;
+   private String status;
+   private String category;
+   private String latestVersion;
+   private String comment;
+   private boolean firmUpdateExist;
+   private boolean configUpdateExist;
+   private String backout;
+   private String updateDate;
+   private String currentVersion;
 
-    /**
-     * @return the nat
-     */
-    public NAT getNat() {
-        return nat;
-    }
+   /**
+    * @return the nat
+    */
+   public NAT getNat() {
+      return nat;
+   }
 
-    /**
-     * @return the directions
-     */
-    public Set<Direction> getDirections() {
-        return directions == null ? ImmutableSet.<Direction> of()
-                : ImmutableSet.copyOf(directions);
-    }
+   /**
+    * @return the directions
+    */
+   public Set<Direction> getDirections() {
+      return directions == null ? ImmutableSet.<Direction> of()
+            : ImmutableSet.copyOf(directions);
+   }
 
-    /**
-     * @return the log
-     */
-    public String getLog() {
-        return log;
-    }
+   /**
+    * @return the log
+    */
+   public String getLog() {
+      return log;
+   }
 
-    /**
-     * @return the status
-     */
-    public String getStatus() {
-        return status;
-    }
+   /**
+    * @return the status
+    */
+   public String getStatus() {
+      return status;
+   }
 
-    /**
-     * @return the category
-     */
-    public String getCategory() {
-        return category;
-    }
+   /**
+    * @return the category
+    */
+   public String getCategory() {
+      return category;
+   }
 
-    /**
-     * @return the latestVersion
-     */
-    public String getLatestVersion() {
-        return latestVersion;
-    }
+   /**
+    * @return the latestVersion
+    */
+   public String getLatestVersion() {
+      return latestVersion;
+   }
 
-    /**
-     * @return the comment
-     */
-    public String getComment() {
-        return comment;
-    }
+   /**
+    * @return the comment
+    */
+   public String getComment() {
+      return comment;
+   }
 
-    /**
-     * @return the firmUpdateExist
-     */
-    public boolean getFirmUpdateExist() {
-        return firmUpdateExist;
-    }
+   /**
+    * @return the firmUpdateExist
+    */
+   public boolean getFirmUpdateExist() {
+      return firmUpdateExist;
+   }
 
-    /**
-     * @return the configUpdateExist
-     */
-    public boolean getConfigUpdateExist() {
-        return configUpdateExist;
-    }
+   /**
+    * @return the configUpdateExist
+    */
+   public boolean getConfigUpdateExist() {
+      return configUpdateExist;
+   }
 
-    /**
-     * @return the backout
-     */
-    public String getBackout() {
-        return backout;
-    }
+   /**
+    * @return the backout
+    */
+   public String getBackout() {
+      return backout;
+   }
 
-    /**
-     * @return the updateDate
-     */
-    public String getUpdateDate() {
-        return updateDate;
-    }
+   /**
+    * @return the updateDate
+    */
+   public String getUpdateDate() {
+      return updateDate;
+   }
 
-    /**
-     * @return the currentVersion
-     */
-    public String getCurrentVersion() {
-        return currentVersion;
-    }
+   /**
+    * @return the currentVersion
+    */
+   public String getCurrentVersion() {
+      return currentVersion;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Group.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Group.java
index 40c36a4..3839285 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Group.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Group.java
@@ -32,195 +32,195 @@
  * @author Dies Koper
  */
 public class Group {
-    private int id;
+   private int id;
 
-    private String protocol;
+   private String protocol;
 
-    private int port1;
+   private int port1;
 
-    private int port2;
+   private int port2;
 
-    private String balanceType;
+   private String balanceType;
 
-    private String uniqueType;
+   private String uniqueType;
 
-    private String monitorType;
+   private String monitorType;
 
-    private int maxConnection;
+   private int maxConnection;
 
-    private int uniqueRetention;
+   private int uniqueRetention;
 
-    private int interval;
+   private int interval;
 
-    private int timeout;
+   private int timeout;
 
-    private int retryCount;
+   private int retryCount;
 
-    private int certNum;
+   private int certNum;
 
-    private Set<Cause> causes;
+   private Set<Cause> causes;
 
-    private RecoveryAction recoveryAction;
+   private RecoveryAction recoveryAction;
 
-    private Set<Target> targets = new LinkedHashSet<Target>();
+   private Set<Target> targets = new LinkedHashSet<Target>();
 
-    private String validity;
+   private String validity;
 
-    enum RecoveryAction {
-        @XmlEnumValue("switch-back")
-        SWITCH_BACK, @XmlEnumValue("maintenance")
-        MAINTENANCE
-    }
+   enum RecoveryAction {
+      @XmlEnumValue("switch-back")
+      SWITCH_BACK, @XmlEnumValue("maintenance")
+      MAINTENANCE
+   }
 
-    /**
-     * @return the id
-     */
-    public int getId() {
-        return id;
-    }
+   /**
+    * @return the id
+    */
+   public int getId() {
+      return id;
+   }
 
-    /**
-     * @return the protocol
-     */
-    public String getProtocol() {
-        return protocol;
-    }
+   /**
+    * @return the protocol
+    */
+   public String getProtocol() {
+      return protocol;
+   }
 
-    /**
-     * @return the port1
-     */
-    public int getPort1() {
-        return port1;
-    }
+   /**
+    * @return the port1
+    */
+   public int getPort1() {
+      return port1;
+   }
 
-    /**
-     * @return the port2
-     */
-    public int getPort2() {
-        return port2;
-    }
+   /**
+    * @return the port2
+    */
+   public int getPort2() {
+      return port2;
+   }
 
-    /**
-     * @return the balanceType
-     */
-    public String getBalanceType() {
-        return balanceType;
-    }
+   /**
+    * @return the balanceType
+    */
+   public String getBalanceType() {
+      return balanceType;
+   }
 
-    /**
-     * @return the uniqueType
-     */
-    public String getUniqueType() {
-        return uniqueType;
-    }
+   /**
+    * @return the uniqueType
+    */
+   public String getUniqueType() {
+      return uniqueType;
+   }
 
-    /**
-     * @return the monitorType
-     */
-    public String getMonitorType() {
-        return monitorType;
-    }
+   /**
+    * @return the monitorType
+    */
+   public String getMonitorType() {
+      return monitorType;
+   }
 
-    /**
-     * @return the maxConnection
-     */
-    public int getMaxConnection() {
-        return maxConnection;
-    }
+   /**
+    * @return the maxConnection
+    */
+   public int getMaxConnection() {
+      return maxConnection;
+   }
 
-    /**
-     * @return the uniqueRetention
-     */
-    public int getUniqueRetention() {
-        return uniqueRetention;
-    }
+   /**
+    * @return the uniqueRetention
+    */
+   public int getUniqueRetention() {
+      return uniqueRetention;
+   }
 
-    /**
-     * @return the interval
-     */
-    public int getInterval() {
-        return interval;
-    }
+   /**
+    * @return the interval
+    */
+   public int getInterval() {
+      return interval;
+   }
 
-    /**
-     * @return the timeout
-     */
-    public int getTimeout() {
-        return timeout;
-    }
+   /**
+    * @return the timeout
+    */
+   public int getTimeout() {
+      return timeout;
+   }
 
-    /**
-     * @return the retryCount
-     */
-    public int getRetryCount() {
-        return retryCount;
-    }
+   /**
+    * @return the retryCount
+    */
+   public int getRetryCount() {
+      return retryCount;
+   }
 
-    /**
-     * @return the certNum
-     */
-    public int getCertNum() {
-        return certNum;
-    }
+   /**
+    * @return the certNum
+    */
+   public int getCertNum() {
+      return certNum;
+   }
 
-    /**
-     * @return the causes
-     */
-    public Set<Cause> getCauses() {
-        return causes == null ? ImmutableSet.<Cause> of() : ImmutableSet
-                .copyOf(causes);
-    }
+   /**
+    * @return the causes
+    */
+   public Set<Cause> getCauses() {
+      return causes == null ? ImmutableSet.<Cause> of() : ImmutableSet
+            .copyOf(causes);
+   }
 
-    /**
-     * @return the recoveryAction
-     */
-    public RecoveryAction getRecoveryAction() {
-        return recoveryAction;
-    }
+   /**
+    * @return the recoveryAction
+    */
+   public RecoveryAction getRecoveryAction() {
+      return recoveryAction;
+   }
 
-    /**
-     * @return the targets
-     */
-    public Set<Target> getTargets() {
-        return targets == null ? ImmutableSet.<Target> of() : ImmutableSet
-                .copyOf(targets);
-    }
+   /**
+    * @return the targets
+    */
+   public Set<Target> getTargets() {
+      return targets == null ? ImmutableSet.<Target> of() : ImmutableSet
+            .copyOf(targets);
+   }
 
-    /**
-     * @return the validity
-     */
-    public String getValidity() {
-        return validity;
-    }
+   /**
+    * @return the validity
+    */
+   public String getValidity() {
+      return validity;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Group that = Group.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Group that = Group.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("protocol", protocol).add("port1", port1)
-                .add("port2", port2).add("balanceType", balanceType)
-                .add("uniqueType", uniqueType).add("monitorType", monitorType)
-                .add("maxConnection", maxConnection)
-                .add("uniqueRetention", uniqueRetention)
-                .add("interval", interval).add("timeout", timeout)
-                .add("retryCount", retryCount).add("certNum", certNum)
-                .add("causes", causes).add("recoveryAction", recoveryAction)
-                .add("targets", targets).add("validity", validity).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("protocol", protocol).add("port1", port1)
+            .add("port2", port2).add("balanceType", balanceType)
+            .add("uniqueType", uniqueType).add("monitorType", monitorType)
+            .add("maxConnection", maxConnection)
+            .add("uniqueRetention", uniqueRetention)
+            .add("interval", interval).add("timeout", timeout)
+            .add("retryCount", retryCount).add("certNum", certNum)
+            .add("causes", causes).add("recoveryAction", recoveryAction)
+            .add("targets", targets).add("validity", validity).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Image.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Image.java
index ed8fbac..2d3be5e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Image.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Image.java
@@ -34,81 +34,81 @@
  * @author Dies Koper
  */
 public class Image {
-    private String id;
+   private String id;
 
-    private String serverCategory;
+   private String serverCategory;
 
-    private String serverApplication;
+   private String serverApplication;
 
-    private String cpuBit;
+   private String cpuBit;
 
-    private float sysvolSize;
+   private float sysvolSize;
 
-    private int numOfMaxDisk;
+   private int numOfMaxDisk;
 
-    private int numOfMaxNic;
+   private int numOfMaxNic;
 
-    @XmlElementWrapper(name = "softwares")
-    @XmlElement(name = "software")
-    private Set<Software> software = new LinkedHashSet<Software>();
+   @XmlElementWrapper(name = "softwares")
+   @XmlElement(name = "software")
+   private Set<Software> software = new LinkedHashSet<Software>();
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public String getServerCategory() {
-        return serverCategory;
-    }
+   public String getServerCategory() {
+      return serverCategory;
+   }
 
-    public String getServerApplication() {
-        return serverApplication;
-    }
+   public String getServerApplication() {
+      return serverApplication;
+   }
 
-    public String getCpuBit() {
-        return cpuBit;
-    }
+   public String getCpuBit() {
+      return cpuBit;
+   }
 
-    public float getSysvolSize() {
-        return sysvolSize;
-    }
+   public float getSysvolSize() {
+      return sysvolSize;
+   }
 
-    public int getNumOfMaxDisk() {
-        return numOfMaxDisk;
-    }
+   public int getNumOfMaxDisk() {
+      return numOfMaxDisk;
+   }
 
-    public int getNumOfMaxNic() {
-        return numOfMaxNic;
-    }
+   public int getNumOfMaxNic() {
+      return numOfMaxNic;
+   }
 
-    public Set<Software> getSoftware() {
-        return software == null ? ImmutableSet.<Software> of() : ImmutableSet
-                .copyOf(software);
-    }
+   public Set<Software> getSoftware() {
+      return software == null ? ImmutableSet.<Software> of() : ImmutableSet
+            .copyOf(software);
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Image that = Image.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Image that = Image.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("serverCategory", serverCategory)
-                .add("serverApplication", serverApplication)
-                .add("cpuBit", cpuBit).add("sysvolSize", sysvolSize)
-                .add("numOfMaxDisk", numOfMaxDisk)
-                .add("numOfMaxNic", numOfMaxNic).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("serverCategory", serverCategory)
+            .add("serverApplication", serverApplication)
+            .add("cpuBit", cpuBit).add("sysvolSize", sysvolSize)
+            .add("numOfMaxDisk", numOfMaxDisk)
+            .add("numOfMaxNic", numOfMaxNic).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Information.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Information.java
index a8a822f..21f292c 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Information.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Information.java
@@ -26,80 +26,80 @@
  * @author Dies Koper
  */
 public class Information {
-    private int seqno;
-    private String title;
-    private String message;
-    private String startDate;
-    private String expiry;
-    private String entryDate;
+   private int seqno;
+   private String title;
+   private String message;
+   private String startDate;
+   private String expiry;
+   private String entryDate;
 
-    /**
-     * @return the seqno
-     */
-    public int getSeqno() {
-        return seqno;
-    }
+   /**
+    * @return the seqno
+    */
+   public int getSeqno() {
+      return seqno;
+   }
 
-    /**
-     * @return the title
-     */
-    public String getTitle() {
-        return title;
-    }
+   /**
+    * @return the title
+    */
+   public String getTitle() {
+      return title;
+   }
 
-    /**
-     * @return the message
-     */
-    public String getMessage() {
-        return message;
-    }
+   /**
+    * @return the message
+    */
+   public String getMessage() {
+      return message;
+   }
 
-    /**
-     * @return the startDate
-     */
-    public String getStartDate() {
-        return startDate;
-    }
+   /**
+    * @return the startDate
+    */
+   public String getStartDate() {
+      return startDate;
+   }
 
-    /**
-     * @return the expiry
-     */
-    public String getExpiry() {
-        return expiry;
-    }
+   /**
+    * @return the expiry
+    */
+   public String getExpiry() {
+      return expiry;
+   }
 
-    /**
-     * @return the entryDate
-     */
-    public String getEntryDate() {
-        return entryDate;
-    }
+   /**
+    * @return the entryDate
+    */
+   public String getEntryDate() {
+      return entryDate;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(seqno, entryDate, message, title);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(seqno, entryDate, message, title);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Information that = Information.class.cast(obj);
-        return Objects.equal(this.seqno, that.seqno)
-                && Objects.equal(this.entryDate, that.entryDate)
-                && Objects.equal(this.message, that.message)
-                && Objects.equal(this.title, that.title);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Information that = Information.class.cast(obj);
+      return Objects.equal(this.seqno, that.seqno)
+            && Objects.equal(this.entryDate, that.entryDate)
+            && Objects.equal(this.message, that.message)
+            && Objects.equal(this.title, that.title);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("seqno", seqno).add("entryDate", entryDate)
-                .add("title", title).add("message", message)
-                .add("startDate", startDate).add("expiry", expiry).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("seqno", seqno).add("entryDate", entryDate)
+            .add("title", title).add("message", message)
+            .add("startDate", startDate).add("expiry", expiry).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/IntermediateCACert.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/IntermediateCACert.java
index 7acc387..879171f 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/IntermediateCACert.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/IntermediateCACert.java
@@ -29,92 +29,92 @@
  */
 @XmlRootElement(name = "ccacert")
 public class IntermediateCACert implements Comparable<IntermediateCACert> {
-    private int ccacertNum;
+   private int ccacertNum;
 
-    private String description;
+   private String description;
 
-    private String subject;
+   private String subject;
 
-    private String issuer;
+   private String issuer;
 
-    private String validity;
+   private String validity;
 
-    private String detail;
+   private String detail;
 
-    /**
-     * @return the ccacertNum
-     */
-    public int getCcacertNum() {
-        return ccacertNum;
-    }
+   /**
+    * @return the ccacertNum
+    */
+   public int getCcacertNum() {
+      return ccacertNum;
+   }
 
-    /**
-     * @return the description
-     */
-    public String getDescription() {
-        return description;
-    }
+   /**
+    * @return the description
+    */
+   public String getDescription() {
+      return description;
+   }
 
-    /**
-     * @return the subject
-     */
-    public String getSubject() {
-        return subject;
-    }
+   /**
+    * @return the subject
+    */
+   public String getSubject() {
+      return subject;
+   }
 
-    /**
-     * @return the issuer
-     */
-    public String getIssuer() {
-        return issuer;
-    }
+   /**
+    * @return the issuer
+    */
+   public String getIssuer() {
+      return issuer;
+   }
 
-    /**
-     * @return the validity
-     */
-    public String getValidity() {
-        return validity;
-    }
+   /**
+    * @return the validity
+    */
+   public String getValidity() {
+      return validity;
+   }
 
-    /**
-     * @return the detail
-     */
-    public String getDetail() {
-        return detail;
-    }
+   /**
+    * @return the detail
+    */
+   public String getDetail() {
+      return detail;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(ccacertNum, issuer, subject, validity);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(ccacertNum, issuer, subject, validity);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        IntermediateCACert that = IntermediateCACert.class.cast(obj);
-        return Objects.equal(this.ccacertNum, that.ccacertNum)
-                && Objects.equal(this.issuer, that.issuer)
-                && Objects.equal(this.subject, that.subject)
-                && Objects.equal(this.validity, that.validity);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      IntermediateCACert that = IntermediateCACert.class.cast(obj);
+      return Objects.equal(this.ccacertNum, that.ccacertNum)
+            && Objects.equal(this.issuer, that.issuer)
+            && Objects.equal(this.subject, that.subject)
+            && Objects.equal(this.validity, that.validity);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("ccacertNum", ccacertNum).add("issuer", issuer)
-                .add("subject", subject).add("validity", validity)
-                .add("description", description).add("detail", detail)
-                .toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("ccacertNum", ccacertNum).add("issuer", issuer)
+            .add("subject", subject).add("validity", validity)
+            .add("description", description).add("detail", detail)
+            .toString();
+   }
 
-    @Override
-    public int compareTo(IntermediateCACert o) {
-        return ccacertNum - o.ccacertNum;
-    }
+   @Override
+   public int compareTo(IntermediateCACert o) {
+      return ccacertNum - o.ccacertNum;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/LoadStatistics.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/LoadStatistics.java
index 654e4fc..9e166af 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/LoadStatistics.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/LoadStatistics.java
@@ -33,36 +33,36 @@
  */
 @XmlRootElement(name = "loadstatistics")
 public class LoadStatistics {
-    private Set<Group> groups = new LinkedHashSet<Group>();
+   private Set<Group> groups = new LinkedHashSet<Group>();
 
-    /**
-     * @return the groups
-     */
-    public Set<Group> getGroups() {
-        return groups == null ? ImmutableSet.<Group> of() : ImmutableSet
-                .copyOf(groups);
-    }
+   /**
+    * @return the groups
+    */
+   public Set<Group> getGroups() {
+      return groups == null ? ImmutableSet.<Group> of() : ImmutableSet
+            .copyOf(groups);
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(groups);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(groups);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        LoadStatistics that = LoadStatistics.class.cast(obj);
-        return Objects.equal(this.groups, that.groups);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      LoadStatistics that = LoadStatistics.class.cast(obj);
+      return Objects.equal(this.groups, that.groups);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("groups", groups).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("groups", groups).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Memory.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Memory.java
index af3b076..d4bd9df 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Memory.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Memory.java
@@ -28,39 +28,39 @@
  * @author Dies Koper
  */
 public class Memory implements Comparable<Memory> {
-    @XmlElement(name = "memorySize")
-    private double size;
+   @XmlElement(name = "memorySize")
+   private double size;
 
-    public double getSize() {
-        return size;
-    }
+   public double getSize() {
+      return size;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(size);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(size);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Memory that = Memory.class.cast(obj);
-        return Objects.equal(this.size, that.size);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Memory that = Memory.class.cast(obj);
+      return Objects.equal(this.size, that.size);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("size", size)
-                .toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("size", size)
+            .toString();
+   }
 
-    @Override
-    public int compareTo(Memory o) {
-        return Double.compare(size, o.size);
-    }
+   @Override
+   public int compareTo(Memory o) {
+      return Double.compare(size, o.size);
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/NAT.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/NAT.java
index a753ed8..d0fcbb2 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/NAT.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/NAT.java
@@ -30,36 +30,36 @@
  * @author Dies Koper
  */
 public class NAT {
-    private Set<Rule> rules = new LinkedHashSet<Rule>();
+   private Set<Rule> rules = new LinkedHashSet<Rule>();
 
-    /**
-     * @return the rules
-     */
-    public Set<Rule> getRules() {
-        return rules == null ? ImmutableSet.<Rule> of() : ImmutableSet
-                .copyOf(rules);
-    }
+   /**
+    * @return the rules
+    */
+   public Set<Rule> getRules() {
+      return rules == null ? ImmutableSet.<Rule> of() : ImmutableSet
+            .copyOf(rules);
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(rules);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(rules);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        NAT that = NAT.class.cast(obj);
-        return Objects.equal(this.rules, that.rules);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      NAT that = NAT.class.cast(obj);
+      return Objects.equal(this.rules, that.rules);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("rules", rules).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("rules", rules).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PerformanceInfo.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PerformanceInfo.java
index e9d9856..37a8b78 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PerformanceInfo.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PerformanceInfo.java
@@ -29,121 +29,121 @@
  */
 @XmlRootElement(name = "performanceinfo")
 public class PerformanceInfo implements Comparable<PerformanceInfo> {
-    private long recordTime;
-    private double cpuUtilization;
-    private long diskReadRequestCount;
-    private long diskWriteRequestCount;
-    private long diskReadSector;
-    private long diskWriteSector;
-    private long nicInputByte;
-    private long nicOutputByte;
-    private long nicInputPacket;
-    private long nicOutputPacket;
+   private long recordTime;
+   private double cpuUtilization;
+   private long diskReadRequestCount;
+   private long diskWriteRequestCount;
+   private long diskReadSector;
+   private long diskWriteSector;
+   private long nicInputByte;
+   private long nicOutputByte;
+   private long nicInputPacket;
+   private long nicOutputPacket;
 
-    /**
-     * @return the recordTime
-     */
-    public long getRecordTime() {
-        return recordTime;
-    }
+   /**
+    * @return the recordTime
+    */
+   public long getRecordTime() {
+      return recordTime;
+   }
 
-    /**
-     * @return the cpuUtilization
-     */
-    public double getCpuUtilization() {
-        return cpuUtilization;
-    }
+   /**
+    * @return the cpuUtilization
+    */
+   public double getCpuUtilization() {
+      return cpuUtilization;
+   }
 
-    /**
-     * @return the diskReadRequestCount
-     */
-    public long getDiskReadRequestCount() {
-        return diskReadRequestCount;
-    }
+   /**
+    * @return the diskReadRequestCount
+    */
+   public long getDiskReadRequestCount() {
+      return diskReadRequestCount;
+   }
 
-    /**
-     * @return the diskWriteRequestCount
-     */
-    public long getDiskWriteRequestCount() {
-        return diskWriteRequestCount;
-    }
+   /**
+    * @return the diskWriteRequestCount
+    */
+   public long getDiskWriteRequestCount() {
+      return diskWriteRequestCount;
+   }
 
-    /**
-     * @return the diskReadSector
-     */
-    public long getDiskReadSector() {
-        return diskReadSector;
-    }
+   /**
+    * @return the diskReadSector
+    */
+   public long getDiskReadSector() {
+      return diskReadSector;
+   }
 
-    /**
-     * @return the diskWriteSector
-     */
-    public long getDiskWriteSector() {
-        return diskWriteSector;
-    }
+   /**
+    * @return the diskWriteSector
+    */
+   public long getDiskWriteSector() {
+      return diskWriteSector;
+   }
 
-    /**
-     * @return the nicInputByte
-     */
-    public long getNicInputByte() {
-        return nicInputByte;
-    }
+   /**
+    * @return the nicInputByte
+    */
+   public long getNicInputByte() {
+      return nicInputByte;
+   }
 
-    /**
-     * @return the nicOutputByte
-     */
-    public long getNicOutputByte() {
-        return nicOutputByte;
-    }
+   /**
+    * @return the nicOutputByte
+    */
+   public long getNicOutputByte() {
+      return nicOutputByte;
+   }
 
-    /**
-     * @return the nicInputPacket
-     */
-    public long getNicInputPacket() {
-        return nicInputPacket;
-    }
+   /**
+    * @return the nicInputPacket
+    */
+   public long getNicInputPacket() {
+      return nicInputPacket;
+   }
 
-    /**
-     * @return the nicOutputPacket
-     */
-    public long getNicOutputPacket() {
-        return nicOutputPacket;
-    }
+   /**
+    * @return the nicOutputPacket
+    */
+   public long getNicOutputPacket() {
+      return nicOutputPacket;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(recordTime);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(recordTime);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        PerformanceInfo that = PerformanceInfo.class.cast(obj);
-        return Objects.equal(this.recordTime, that.recordTime);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      PerformanceInfo that = PerformanceInfo.class.cast(obj);
+      return Objects.equal(this.recordTime, that.recordTime);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("recordTime", recordTime)
-                .add("cpuUtilization", cpuUtilization)
-                .add("diskReadRequestCount", diskReadRequestCount)
-                .add("diskWriteRequestCount", diskWriteRequestCount)
-                .add("diskReadSector", diskReadSector)
-                .add("diskWriteSector", diskWriteSector)
-                .add("nicInputByte", nicInputByte)
-                .add("nicOutputByte", nicOutputByte)
-                .add("nicInputPacket", nicInputPacket)
-                .add("nicOutputPacket", nicOutputPacket).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("recordTime", recordTime)
+            .add("cpuUtilization", cpuUtilization)
+            .add("diskReadRequestCount", diskReadRequestCount)
+            .add("diskWriteRequestCount", diskWriteRequestCount)
+            .add("diskReadSector", diskReadSector)
+            .add("diskWriteSector", diskWriteSector)
+            .add("nicInputByte", nicInputByte)
+            .add("nicOutputByte", nicOutputByte)
+            .add("nicInputPacket", nicInputPacket)
+            .add("nicOutputPacket", nicOutputPacket).toString();
+   }
 
-    @Override
-    public int compareTo(PerformanceInfo o) {
-        return (int) (recordTime - o.recordTime);
-    }
+   @Override
+   public int compareTo(PerformanceInfo o) {
+      return (int) (recordTime - o.recordTime);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Period.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Period.java
index b75173f..718af01 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Period.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Period.java
@@ -25,37 +25,37 @@
  * @author Dies Koper
  */
 public class Period {
-    private String current;
-    private String before;
-    private String today;
-    private String yesterday;
+   private String current;
+   private String before;
+   private String today;
+   private String yesterday;
 
-    /**
-     * @return the current
-     */
-    public String getCurrent() {
-        return current;
-    }
+   /**
+    * @return the current
+    */
+   public String getCurrent() {
+      return current;
+   }
 
-    /**
-     * @return the before
-     */
-    public String getBefore() {
-        return before;
-    }
+   /**
+    * @return the before
+    */
+   public String getBefore() {
+      return before;
+   }
 
-    /**
-     * @return the today
-     */
-    public String getToday() {
-        return today;
-    }
+   /**
+    * @return the today
+    */
+   public String getToday() {
+      return today;
+   }
 
-    /**
-     * @return the yesterday
-     */
-    public String getYesterday() {
-        return yesterday;
-    }
+   /**
+    * @return the yesterday
+    */
+   public String getYesterday() {
+      return yesterday;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Policy.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Policy.java
index e030c12..4c7c167 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Policy.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Policy.java
@@ -28,168 +28,168 @@
  * @author Dies Koper
  */
 public class Policy implements Comparable<Policy> {
-    private int id;
+   private int id;
 
-    private String src;
+   private String src;
 
-    private PolicyType srcType;
+   private PolicyType srcType;
 
-    private String srcPort;
+   private String srcPort;
 
-    private Service dstService;
+   private Service dstService;
 
-    private String dst;
+   private String dst;
 
-    private PolicyType dstType;
+   private PolicyType dstType;
 
-    private String dstPort;
+   private String dstPort;
 
-    private Protocol protocol;
+   private Protocol protocol;
 
-    private Action action;
+   private Action action;
 
-    private Log log;
+   private Log log;
 
-    enum Service {
-        NONE, WSUS, DNS, NTP, @XmlEnumValue("yum")
-        YUM, KMS, @XmlEnumValue("Symantec")
-        SYMANTEC, RHUI
-    }
+   enum Service {
+      NONE, WSUS, DNS, NTP, @XmlEnumValue("yum")
+      YUM, KMS, @XmlEnumValue("Symantec")
+      SYMANTEC, RHUI
+   }
 
-    enum PolicyType {IP, FQDN, FQDNF}
+   enum PolicyType {IP, FQDN, FQDNF}
 
-    enum Protocol {
-        @XmlEnumValue("tcp")
-        TCP, @XmlEnumValue("udp")
-        UDP, @XmlEnumValue("tcp-udp")
-        TCP_UDP, @XmlEnumValue("icmp")
-        ICMP
-    }
+   enum Protocol {
+      @XmlEnumValue("tcp")
+      TCP, @XmlEnumValue("udp")
+      UDP, @XmlEnumValue("tcp-udp")
+      TCP_UDP, @XmlEnumValue("icmp")
+      ICMP
+   }
 
-    enum Action {
-        @XmlEnumValue("Accept")
-        ACCEPT, @XmlEnumValue("Deny")
-        DENY
-    }
+   enum Action {
+      @XmlEnumValue("Accept")
+      ACCEPT, @XmlEnumValue("Deny")
+      DENY
+   }
 
-    enum Log {
-        @XmlEnumValue("On")
-        ON, @XmlEnumValue("Off")
-        OFF
-    }
+   enum Log {
+      @XmlEnumValue("On")
+      ON, @XmlEnumValue("Off")
+      OFF
+   }
 
-    /**
-     * @return the id
-     */
-    public int getId() {
-        return id;
-    }
+   /**
+    * @return the id
+    */
+   public int getId() {
+      return id;
+   }
 
-    /**
-     * @return the src
-     */
-    public String getSrc() {
-        return src;
-    }
+   /**
+    * @return the src
+    */
+   public String getSrc() {
+      return src;
+   }
 
-    /**
-     * @return the srcType
-     */
-    public PolicyType getSrcType() {
-        return srcType;
-    }
+   /**
+    * @return the srcType
+    */
+   public PolicyType getSrcType() {
+      return srcType;
+   }
 
-    /**
-     * @return the srcPort
-     */
-    public String getSrcPort() {
-        return srcPort;
-    }
+   /**
+    * @return the srcPort
+    */
+   public String getSrcPort() {
+      return srcPort;
+   }
 
-    /**
-     * @return the dstService
-     */
-    public Service getDstService() {
-        return dstService;
-    }
+   /**
+    * @return the dstService
+    */
+   public Service getDstService() {
+      return dstService;
+   }
 
-    /**
-     * @return the dst
-     */
-    public String getDst() {
-        return dst;
-    }
+   /**
+    * @return the dst
+    */
+   public String getDst() {
+      return dst;
+   }
 
-    /**
-     * @return the dstType
-     */
-    public PolicyType getDstType() {
-        return dstType;
-    }
+   /**
+    * @return the dstType
+    */
+   public PolicyType getDstType() {
+      return dstType;
+   }
 
-    /**
-     * @return the dstPort
-     */
-    public String getDstPort() {
-        return dstPort;
-    }
+   /**
+    * @return the dstPort
+    */
+   public String getDstPort() {
+      return dstPort;
+   }
 
-    /**
-     * @return the protocol
-     */
-    public Protocol getProtocol() {
-        return protocol;
-    }
+   /**
+    * @return the protocol
+    */
+   public Protocol getProtocol() {
+      return protocol;
+   }
 
-    /**
-     * @return the action
-     */
-    public Action getAction() {
-        return action;
-    }
+   /**
+    * @return the action
+    */
+   public Action getAction() {
+      return action;
+   }
 
-    /**
-     * @return the log
-     */
-    public Log getLog() {
-        return log;
-    }
+   /**
+    * @return the log
+    */
+   public Log getLog() {
+      return log;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Policy that = Policy.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Policy that = Policy.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("id", id)
-                .add("src", src)
-                .add("srcType", srcType)
-                .add("srcPort", srcPort)
-                .add("dstService", dstService)
-                .add("dst", dst)
-                .add("dstType", dstType)
-                .add("dstPort", dstPort)
-                .add("protocol", protocol)
-                .add("action", action)
-                .add("log", log).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("id", id)
+            .add("src", src)
+            .add("srcType", srcType)
+            .add("srcPort", srcPort)
+            .add("dstService", dstService)
+            .add("dst", dst)
+            .add("dstType", dstType)
+            .add("dstPort", dstPort)
+            .add("protocol", protocol)
+            .add("action", action)
+            .add("log", log).toString();
+   }
 
-    @Override
-    public int compareTo(Policy o) {
-        return id - o.id;
-    }
+   @Override
+   public int compareTo(Policy o) {
+      return id - o.id;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Product.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Product.java
index 447f81e..c176589 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Product.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Product.java
@@ -28,57 +28,57 @@
  * @author Dies Koper
  */
 public class Product {
-    @XmlElement(name = "productName")
-    private String name;
+   @XmlElement(name = "productName")
+   private String name;
 
-    private String unitName;
+   private String unitName;
 
-    private String usedPoints;
+   private String usedPoints;
 
-    /**
-     * @return the name
-     */
-    public String getName() {
-        return name;
-    }
+   /**
+    * @return the name
+    */
+   public String getName() {
+      return name;
+   }
 
-    /**
-     * @return the unitName
-     */
-    public String getUnitName() {
-        return unitName;
-    }
+   /**
+    * @return the unitName
+    */
+   public String getUnitName() {
+      return unitName;
+   }
 
-    /**
-     * @return the usedPoints
-     */
-    public String getUsedPoints() {
-        return usedPoints;
-    }
+   /**
+    * @return the usedPoints
+    */
+   public String getUsedPoints() {
+      return usedPoints;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(name, unitName, usedPoints);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(name, unitName, usedPoints);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Product that = Product.class.cast(obj);
-        return Objects.equal(this.name, that.name)
-                && Objects.equal(this.unitName, that.unitName)
-                && Objects.equal(this.usedPoints, that.usedPoints);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Product that = Product.class.cast(obj);
+      return Objects.equal(this.name, that.name)
+            && Objects.equal(this.unitName, that.unitName)
+            && Objects.equal(this.usedPoints, that.usedPoints);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("name", name)
-                .add("unitName", unitName).add("usedPoints", usedPoints)
-                .toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("name", name)
+            .add("unitName", unitName).add("usedPoints", usedPoints)
+            .toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PublicIP.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PublicIP.java
index 698c462..c672815 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PublicIP.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PublicIP.java
@@ -36,59 +36,59 @@
  */
 public class PublicIP {
 
-    public static enum Version {
-        IPv4, IPv6, UNRECOGNIZED;
+   public static enum Version {
+      IPv4, IPv6, UNRECOGNIZED;
 
-        @Override
-        public String toString() {
-            return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL,
-                    name());
-        }
+      @Override
+      public String toString() {
+         return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL,
+               name());
+      }
 
-        public static Version fromValue(String version) {
-            try {
-                return valueOf(CaseFormat.UPPER_CAMEL.to(
-                        CaseFormat.UPPER_UNDERSCORE,
-                        checkNotNull(version, "version")));
-            } catch (IllegalArgumentException e) {
-                return UNRECOGNIZED;
-            }
-        }
+      public static Version fromValue(String version) {
+         try {
+            return valueOf(CaseFormat.UPPER_CAMEL.to(
+                  CaseFormat.UPPER_UNDERSCORE,
+                  checkNotNull(version, "version")));
+         } catch (IllegalArgumentException e) {
+            return UNRECOGNIZED;
+         }
+      }
 
-    }
+   }
 
-    protected String address;
-    @XmlElement(name = "v4v6Flag")
-    protected Version version;
+   protected String address;
+   @XmlElement(name = "v4v6Flag")
+   protected Version version;
 
-    public String getAddress() {
-        return address;
-    }
+   public String getAddress() {
+      return address;
+   }
 
-    public Version getVersion() {
-        return version;
-    }
+   public Version getVersion() {
+      return version;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(address);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(address);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        PublicIP that = PublicIP.class.cast(obj);
-        return Objects.equal(this.address, that.address);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      PublicIP that = PublicIP.class.cast(obj);
+      return Objects.equal(this.address, that.address);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("address", address).add("version", version).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("address", address).add("version", version).toString();
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PublicIPStatus.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PublicIPStatus.java
index 3b10c95..aa93809 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PublicIPStatus.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/PublicIPStatus.java
@@ -18,12 +18,12 @@
  */
 package org.jclouds.fujitsu.fgcp.domain;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import javax.xml.bind.annotation.XmlRootElement;
 
 import com.google.common.base.CaseFormat;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 /**
  * Possible statuses of a public IP address.
  * <p>
@@ -34,24 +34,24 @@
  */
 @XmlRootElement(name = "publicipStatus")
 public enum PublicIPStatus {
-    ATTACHED, ATTACHING, DETACHING, DETACHED, UNRECOGNIZED;
+   ATTACHED, ATTACHING, DETACHING, DETACHED, UNRECOGNIZED;
 
-    public String value() {
-        return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
-    }
+   public String value() {
+      return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
+   }
 
-    @Override
-    public String toString() {
-        return value();
-    }
+   @Override
+   public String toString() {
+      return value();
+   }
 
-    public static PublicIPStatus fromValue(String status) {
-        try {
-            return valueOf(CaseFormat.UPPER_CAMEL
-                    .to(CaseFormat.UPPER_UNDERSCORE,
-                            checkNotNull(status, "status")));
-        } catch (IllegalArgumentException e) {
-            return UNRECOGNIZED;
-        }
-    }
+   public static PublicIPStatus fromValue(String status) {
+      try {
+         return valueOf(CaseFormat.UPPER_CAMEL
+               .to(CaseFormat.UPPER_UNDERSCORE,
+                     checkNotNull(status, "status")));
+      } catch (IllegalArgumentException e) {
+         return UNRECOGNIZED;
+      }
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Rule.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Rule.java
index 6cd9798..3dc45ca 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Rule.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Rule.java
@@ -31,54 +31,54 @@
  * @author Dies Koper
  */
 public class Rule {
-    private String publicIp;
-    private String privateIp;
-    private boolean snapt;
+   private String publicIp;
+   private String privateIp;
+   private boolean snapt;
 
-    /**
-     * @return the publicIp
-     */
-    public String getPublicIp() {
-        return publicIp;
-    }
+   /**
+    * @return the publicIp
+    */
+   public String getPublicIp() {
+      return publicIp;
+   }
 
-    /**
-     * @return the privateIp
-     */
-    public String getPrivateIp() {
-        return privateIp;
-    }
+   /**
+    * @return the privateIp
+    */
+   public String getPrivateIp() {
+      return privateIp;
+   }
 
-    /**
-     * @return the snapt
-     */
-    public boolean isSnapt() {
-        return snapt;
-    }
+   /**
+    * @return the snapt
+    */
+   public boolean isSnapt() {
+      return snapt;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(privateIp, publicIp, snapt);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(privateIp, publicIp, snapt);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Rule that = Rule.class.cast(obj);
-        return Objects.equal(this.privateIp, that.privateIp)
-                && Objects.equal(this.publicIp, that.publicIp)
-                && Objects.equal(this.snapt, that.snapt);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Rule that = Rule.class.cast(obj);
+      return Objects.equal(this.privateIp, that.privateIp)
+            && Objects.equal(this.publicIp, that.publicIp)
+            && Objects.equal(this.snapt, that.snapt);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("privateIp", privateIp).add("publicIp", publicIp)
-                .add("snapt", snapt).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("privateIp", privateIp).add("publicIp", publicIp)
+            .add("snapt", snapt).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/SLB.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/SLB.java
index 274c3b8..40a0695 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/SLB.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/SLB.java
@@ -32,169 +32,169 @@
  */
 @XmlRootElement(name = "slb")
 public class SLB extends BuiltinServer {
-    private String ipAddress;
+   private String ipAddress;
 
-    private Set<IntermediateCACert> ccacerts = new LinkedHashSet<IntermediateCACert>();
+   private Set<IntermediateCACert> ccacerts = new LinkedHashSet<IntermediateCACert>();
 
-    private Set<ServerCert> servercerts = new LinkedHashSet<ServerCert>();
+   private Set<ServerCert> servercerts = new LinkedHashSet<ServerCert>();
 
-    private Set<Group> groups;
+   private Set<Group> groups;
 
-    private String srcType;
+   private String srcType;
 
-    private String srcPort;
+   private String srcPort;
 
-    private String status;
+   private String status;
 
-    private ErrorStatistics errorStatistics;
+   private ErrorStatistics errorStatistics;
 
-    private LoadStatistics loadStatistics;
+   private LoadStatistics loadStatistics;
 
-    private String category;
+   private String category;
 
-    private String latestVersion;
+   private String latestVersion;
 
-    private String comment;
+   private String comment;
 
-    private boolean firmUpdateExist;
+   private boolean firmUpdateExist;
 
-    private boolean configUpdateExist;
+   private boolean configUpdateExist;
 
-    private boolean backout;
+   private boolean backout;
 
-    private String updateDate;
+   private String updateDate;
 
-    private String currentVersion;
+   private String currentVersion;
 
-    private String webAccelerator;
+   private String webAccelerator;
 
-    /**
-     * @return the ipAddress
-     */
-    public String getIpAddress() {
-        return ipAddress;
-    }
+   /**
+    * @return the ipAddress
+    */
+   public String getIpAddress() {
+      return ipAddress;
+   }
 
-    /**
-     * @return the ccacerts
-     */
-    public Set<IntermediateCACert> getCcacerts() {
-        return ccacerts == null ? ImmutableSet.<IntermediateCACert> of()
-                : ImmutableSet.copyOf(ccacerts);
-    }
+   /**
+    * @return the ccacerts
+    */
+   public Set<IntermediateCACert> getCcacerts() {
+      return ccacerts == null ? ImmutableSet.<IntermediateCACert> of()
+            : ImmutableSet.copyOf(ccacerts);
+   }
 
-    /**
-     * @return the servercerts
-     */
-    public Set<ServerCert> getServercerts() {
-        return servercerts == null ? ImmutableSet.<ServerCert> of()
-                : ImmutableSet.copyOf(servercerts);
-    }
+   /**
+    * @return the servercerts
+    */
+   public Set<ServerCert> getServercerts() {
+      return servercerts == null ? ImmutableSet.<ServerCert> of()
+            : ImmutableSet.copyOf(servercerts);
+   }
 
-    /**
-     * @return the groups
-     */
-    public Set<Group> getGroups() {
-        return groups == null ? ImmutableSet.<Group> of() : ImmutableSet
-                .copyOf(groups);
-    }
+   /**
+    * @return the groups
+    */
+   public Set<Group> getGroups() {
+      return groups == null ? ImmutableSet.<Group> of() : ImmutableSet
+            .copyOf(groups);
+   }
 
-    /**
-     * @return the srcType
-     */
-    public String getSrcType() {
-        return srcType;
-    }
+   /**
+    * @return the srcType
+    */
+   public String getSrcType() {
+      return srcType;
+   }
 
-    /**
-     * @return the srcPort
-     */
-    public String getSrcPort() {
-        return srcPort;
-    }
+   /**
+    * @return the srcPort
+    */
+   public String getSrcPort() {
+      return srcPort;
+   }
 
-    /**
-     * @return the status
-     */
-    public String getStatus() {
-        return status;
-    }
+   /**
+    * @return the status
+    */
+   public String getStatus() {
+      return status;
+   }
 
-    /**
-     * @return the errorStatistics
-     */
-    public ErrorStatistics getErrorStatistics() {
-        return errorStatistics;
-    }
+   /**
+    * @return the errorStatistics
+    */
+   public ErrorStatistics getErrorStatistics() {
+      return errorStatistics;
+   }
 
-    /**
-     * @return the loadStatistics
-     */
-    public LoadStatistics getLoadStatistics() {
-        return loadStatistics;
-    }
+   /**
+    * @return the loadStatistics
+    */
+   public LoadStatistics getLoadStatistics() {
+      return loadStatistics;
+   }
 
-    /**
-     * @return the category
-     */
-    public String getCategory() {
-        return category;
-    }
+   /**
+    * @return the category
+    */
+   public String getCategory() {
+      return category;
+   }
 
-    /**
-     * @return the latestVersion
-     */
-    public String getLatestVersion() {
-        return latestVersion;
-    }
+   /**
+    * @return the latestVersion
+    */
+   public String getLatestVersion() {
+      return latestVersion;
+   }
 
-    /**
-     * @return the comment
-     */
-    public String getComment() {
-        return comment;
-    }
+   /**
+    * @return the comment
+    */
+   public String getComment() {
+      return comment;
+   }
 
-    /**
-     * @return the firmUpdateExist
-     */
-    public boolean getFirmUpdateExist() {
-        return firmUpdateExist;
-    }
+   /**
+    * @return the firmUpdateExist
+    */
+   public boolean getFirmUpdateExist() {
+      return firmUpdateExist;
+   }
 
-    /**
-     * @return the configUpdateExist
-     */
-    public boolean getConfigUpdateExist() {
-        return configUpdateExist;
-    }
+   /**
+    * @return the configUpdateExist
+    */
+   public boolean getConfigUpdateExist() {
+      return configUpdateExist;
+   }
 
-    /**
-     * @return the backout
-     */
-    public boolean getBackout() {
-        return backout;
-    }
+   /**
+    * @return the backout
+    */
+   public boolean getBackout() {
+      return backout;
+   }
 
-    /**
-     * @return the updateDate
-     */
-    public String getUpdateDate() {
-        return updateDate;
-    }
+   /**
+    * @return the updateDate
+    */
+   public String getUpdateDate() {
+      return updateDate;
+   }
 
-    /**
-     * @return the currentVersion
-     */
-    public String getCurrentVersion() {
-        return currentVersion;
-    }
+   /**
+    * @return the currentVersion
+    */
+   public String getCurrentVersion() {
+      return currentVersion;
+   }
 
-    /**
-     * @return the webAccelerator
-     */
-    public String getWebAccelerator() {
-        return webAccelerator;
-    }
+   /**
+    * @return the webAccelerator
+    */
+   public String getWebAccelerator() {
+      return webAccelerator;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ServerCert.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ServerCert.java
index d1dfc06..3df227f 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ServerCert.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ServerCert.java
@@ -29,93 +29,93 @@
  */
 @XmlRootElement(name = "servercert")
 public class ServerCert implements Comparable<ServerCert> {
-    private int certNum;
+   private int certNum;
 
-    private String subject;
+   private String subject;
 
-    private String issuer;
+   private String issuer;
 
-    private String validity;
+   private String validity;
 
-    private int groupId;
+   private int groupId;
 
-    private String detail;
+   private String detail;
 
-    /**
-     * @return the certNum
-     */
-    public int getCertNum() {
-        return certNum;
-    }
+   /**
+    * @return the certNum
+    */
+   public int getCertNum() {
+      return certNum;
+   }
 
-    /**
-     * @return the subject
-     */
-    public String getSubject() {
-        return subject;
-    }
+   /**
+    * @return the subject
+    */
+   public String getSubject() {
+      return subject;
+   }
 
-    /**
-     * @return the issuer
-     */
-    public String getIssuer() {
-        return issuer;
-    }
+   /**
+    * @return the issuer
+    */
+   public String getIssuer() {
+      return issuer;
+   }
 
-    /**
-     * @return the validity
-     */
-    public String getValidity() {
-        return validity;
-    }
+   /**
+    * @return the validity
+    */
+   public String getValidity() {
+      return validity;
+   }
 
-    /**
-     * @return the groupId
-     */
-    public int getGroupId() {
-        return groupId;
-    }
+   /**
+    * @return the groupId
+    */
+   public int getGroupId() {
+      return groupId;
+   }
 
-    /**
-     * @return the detail
-     */
-    public String getDetail() {
-        return detail;
-    }
+   /**
+    * @return the detail
+    */
+   public String getDetail() {
+      return detail;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(certNum, groupId, issuer, subject, validity);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(certNum, groupId, issuer, subject, validity);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        ServerCert that = ServerCert.class.cast(obj);
-        return Objects.equal(this.certNum, that.certNum)
-                && Objects.equal(this.groupId, that.groupId)
-                && Objects.equal(this.issuer, that.issuer)
-                && Objects.equal(this.subject, that.subject)
-                && Objects.equal(this.validity, that.validity);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      ServerCert that = ServerCert.class.cast(obj);
+      return Objects.equal(this.certNum, that.certNum)
+            && Objects.equal(this.groupId, that.groupId)
+            && Objects.equal(this.issuer, that.issuer)
+            && Objects.equal(this.subject, that.subject)
+            && Objects.equal(this.validity, that.validity);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("certNum", certNum).add("issuer", issuer)
-                .add("subject", subject).add("validity", validity)
-                .add("groupId", groupId).add("detail", detail).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("certNum", certNum).add("issuer", issuer)
+            .add("subject", subject).add("validity", validity)
+            .add("groupId", groupId).add("detail", detail).toString();
+   }
 
-    @Override
-    public int compareTo(ServerCert o) {
-        return (certNum - o.certNum) == 0 ? (groupId - o.groupId)
-                : (certNum - o.certNum);
-    }
+   @Override
+   public int compareTo(ServerCert o) {
+      return (certNum - o.certNum) == 0 ? (groupId - o.groupId)
+            : (certNum - o.certNum);
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ServerType.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ServerType.java
index b4a7248..c5a8b36 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ServerType.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/ServerType.java
@@ -35,111 +35,111 @@
  */
 @XmlRootElement(name = "servertype")
 public class ServerType implements Comparable<ServerType> {
-    private String id;
+   private String id;
 
-    private String name;
+   private String name;
 
-    private String label;
+   private String label;
 
-    private String comment;
+   private String comment;
 
-    private String productId;
+   private String productId;
 
-    private String productName;
+   private String productName;
 
-    private String price;
+   private String price;
 
-    private String chargeType;
+   private String chargeType;
 
-    private String expectedUsage;
+   private String expectedUsage;
 
-    private CPU cpu;
+   private CPU cpu;
 
-    private Memory memory;
+   private Memory memory;
 
-    @XmlElementWrapper(name = "disks")
-    @XmlElement(name = "disk")
-    private Set<Disk> disks = Sets.newLinkedHashSet();
+   @XmlElementWrapper(name = "disks")
+   @XmlElement(name = "disk")
+   private Set<Disk> disks = Sets.newLinkedHashSet();
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public String getName() {
-        return name;
-    }
+   public String getName() {
+      return name;
+   }
 
-    public String getLabel() {
-        return label;
-    }
+   public String getLabel() {
+      return label;
+   }
 
-    public String getComment() {
-        return comment;
-    }
+   public String getComment() {
+      return comment;
+   }
 
-    public String getProductId() {
-        return productId;
-    }
+   public String getProductId() {
+      return productId;
+   }
 
-    public String getProductName() {
-        return productName;
-    }
+   public String getProductName() {
+      return productName;
+   }
 
-    public String getPrice() {
-        return price;
-    }
+   public String getPrice() {
+      return price;
+   }
 
-    public String getChargeType() {
-        return chargeType;
-    }
+   public String getChargeType() {
+      return chargeType;
+   }
 
-    public String getExpectedUsage() {
-        return expectedUsage;
-    }
+   public String getExpectedUsage() {
+      return expectedUsage;
+   }
 
-    public CPU getCpu() {
-        return cpu;
-    }
+   public CPU getCpu() {
+      return cpu;
+   }
 
-    public Memory getMemory() {
-        return memory;
-    }
+   public Memory getMemory() {
+      return memory;
+   }
 
-    public Set<Disk> getDisks() {
-        return disks == null ? ImmutableSet.<Disk> of() : ImmutableSet
-                .copyOf(disks);
-    }
+   public Set<Disk> getDisks() {
+      return disks == null ? ImmutableSet.<Disk> of() : ImmutableSet
+            .copyOf(disks);
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        ServerType that = ServerType.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      ServerType that = ServerType.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("label", label).add("comment", comment)
-                .add("productId", productId).add("productName", productName)
-                .add("price", price).add("chargeType", chargeType)
-                .add("expectedUsage", expectedUsage).add("cpu", cpu)
-                .add("memory", memory).add("disks", disks).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("label", label).add("comment", comment)
+            .add("productId", productId).add("productName", productName)
+            .add("price", price).add("chargeType", chargeType)
+            .add("expectedUsage", expectedUsage).add("cpu", cpu)
+            .add("memory", memory).add("disks", disks).toString();
+   }
 
-    @Override
-    public int compareTo(ServerType o) {
-        return memory == null ? -1 : memory.compareTo(o.memory);
-    }
+   @Override
+   public int compareTo(ServerType o) {
+      return memory == null ? -1 : memory.compareTo(o.memory);
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Software.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Software.java
index cfff2a6..0bf955a 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Software.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Software.java
@@ -26,78 +26,78 @@
  * @author Dies Koper
  */
 public class Software {
-    private String name;
+   private String name;
 
-    private String id;
+   private String id;
 
-    private String category;
+   private String category;
 
-    private String version;
+   private String version;
 
-    private String officialVersion;
+   private String officialVersion;
 
-    private String patch;
+   private String patch;
 
-    private String license;
+   private String license;
 
-    private String support;
+   private String support;
 
-    public String getName() {
-        return name;
-    }
+   public String getName() {
+      return name;
+   }
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public String getCategory() {
-        return category;
-    }
+   public String getCategory() {
+      return category;
+   }
 
-    public String getVersion() {
-        return version;
-    }
+   public String getVersion() {
+      return version;
+   }
 
-    public String getOfficialVersion() {
-        return officialVersion;
-    }
+   public String getOfficialVersion() {
+      return officialVersion;
+   }
 
-    public String getPatch() {
-        return patch;
-    }
+   public String getPatch() {
+      return patch;
+   }
 
-    public String getLicense() {
-        return license;
-    }
+   public String getLicense() {
+      return license;
+   }
 
-    public String getSupport() {
-        return support;
-    }
+   public String getSupport() {
+      return support;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Software that = Software.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Software that = Software.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("category", category)
-                .add("version", version)
-                .add("officialVersion", officialVersion)
-                .add("support", support).add("patch", patch)
-                .add("license", license).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("category", category)
+            .add("version", version)
+            .add("officialVersion", officialVersion)
+            .add("support", support).add("patch", patch)
+            .add("license", license).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Target.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Target.java
index 44cd0fe..aeb340f 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Target.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/Target.java
@@ -26,101 +26,101 @@
  * @author Dies Koper
  */
 public class Target {
-    private String serverId;
+   private String serverId;
 
-    private String serverName;
+   private String serverName;
 
-    private String ipAddress;
+   private String ipAddress;
 
-    private String port1;
+   private String port1;
 
-    private String port2;
+   private String port2;
 
-    private String status;
+   private String status;
 
-    private String now;
+   private String now;
 
-    private String peak;
+   private String peak;
 
-    /**
-     * @return the serverId
-     */
-    public String getServerId() {
-        return serverId;
-    }
+   /**
+    * @return the serverId
+    */
+   public String getServerId() {
+      return serverId;
+   }
 
-    /**
-     * @return the serverName
-     */
-    public String getServerName() {
-        return serverName;
-    }
+   /**
+    * @return the serverName
+    */
+   public String getServerName() {
+      return serverName;
+   }
 
-    /**
-     * @return the ipAddress
-     */
-    public String getIpAddress() {
-        return ipAddress;
-    }
+   /**
+    * @return the ipAddress
+    */
+   public String getIpAddress() {
+      return ipAddress;
+   }
 
-    /**
-     * @return the port1
-     */
-    public String getPort1() {
-        return port1;
-    }
+   /**
+    * @return the port1
+    */
+   public String getPort1() {
+      return port1;
+   }
 
-    /**
-     * @return the port2
-     */
-    public String getPort2() {
-        return port2;
-    }
+   /**
+    * @return the port2
+    */
+   public String getPort2() {
+      return port2;
+   }
 
-    /**
-     * @return the status
-     */
-    public String getStatus() {
-        return status;
-    }
+   /**
+    * @return the status
+    */
+   public String getStatus() {
+      return status;
+   }
 
-    /**
-     * @return the now
-     */
-    public String getNow() {
-        return now;
-    }
+   /**
+    * @return the now
+    */
+   public String getNow() {
+      return now;
+   }
 
-    /**
-     * @return the peak
-     */
-    public String getPeak() {
-        return peak;
-    }
+   /**
+    * @return the peak
+    */
+   public String getPeak() {
+      return peak;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(serverId);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(serverId);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Target that = Target.class.cast(obj);
-        return Objects.equal(this.serverId, that.serverId);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      Target that = Target.class.cast(obj);
+      return Objects.equal(this.serverId, that.serverId);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("serverId", serverId).add("serverName", serverName)
-                .add("ipAddress", ipAddress).add("port1", port1)
-                .add("port2", port2).add("status", status).add("now", now)
-                .add("peak", peak).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("serverId", serverId).add("serverName", serverName)
+            .add("ipAddress", ipAddress).add("port1", port1)
+            .add("port2", port2).add("status", status).add("now", now)
+            .add("peak", peak).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/UsageInfo.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/UsageInfo.java
index 48cffa4..61c4b36 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/UsageInfo.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/UsageInfo.java
@@ -35,60 +35,60 @@
  */
 @XmlRootElement(name = "usageinfo")
 public class UsageInfo {
-    @XmlElement(name = "vsysId")
-    private String systemId;
-    @XmlElement(name = "vsysName")
-    private String systemName;
+   @XmlElement(name = "vsysId")
+   private String systemId;
+   @XmlElement(name = "vsysName")
+   private String systemName;
 
-    @XmlElementWrapper(name = "products")
-    @XmlElement(name = "product")
-    private Set<Product> products = new LinkedHashSet<Product>();
+   @XmlElementWrapper(name = "products")
+   @XmlElement(name = "product")
+   private Set<Product> products = new LinkedHashSet<Product>();
 
-    /**
-     * @return the systemId
-     */
-    public String getSystemId() {
-        return systemId;
-    }
+   /**
+    * @return the systemId
+    */
+   public String getSystemId() {
+      return systemId;
+   }
 
-    /**
-     * @return the systemName
-     */
-    public String getSystemName() {
-        return systemName;
-    }
+   /**
+    * @return the systemName
+    */
+   public String getSystemName() {
+      return systemName;
+   }
 
-    /**
-     * @return the products
-     */
-    public Set<Product> getProducts() {
-        return products == null ? ImmutableSet.<Product> of() : ImmutableSet
-                .copyOf(products);
-    }
+   /**
+    * @return the products
+    */
+   public Set<Product> getProducts() {
+      return products == null ? ImmutableSet.<Product> of() : ImmutableSet
+            .copyOf(products);
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(systemId, systemName, products);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(systemId, systemName, products);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        UsageInfo that = UsageInfo.class.cast(obj);
-        return Objects.equal(this.systemId, that.systemId)
-                && Objects.equal(this.systemName, that.systemName)
-                && Objects.equal(this.products, that.products);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      UsageInfo that = UsageInfo.class.cast(obj);
+      return Objects.equal(this.systemId, that.systemId)
+            && Objects.equal(this.systemName, that.systemName)
+            && Objects.equal(this.products, that.products);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("systemId", systemId).add("systemName", systemName)
-                .add("products", products).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("systemId", systemId).add("systemName", systemName)
+            .add("products", products).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VDisk.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VDisk.java
index e8784c4..e90815e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VDisk.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VDisk.java
@@ -30,57 +30,57 @@
  */
 @XmlRootElement(name = "vdisk")
 public class VDisk {
-    @XmlElement(name = "diskId")
-    private String id;
-    @XmlElement(name = "diskName")
-    private String name;
-    @XmlElement(name = "attachedTo")
-    private String attachedServer;
-    private String creator;
-    private double size;
+   @XmlElement(name = "diskId")
+   private String id;
+   @XmlElement(name = "diskName")
+   private String name;
+   @XmlElement(name = "attachedTo")
+   private String attachedServer;
+   private String creator;
+   private double size;
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public String getName() {
-        return name;
-    }
+   public String getName() {
+      return name;
+   }
 
-    public String getAttachedServer() {
-        return attachedServer;
-    }
+   public String getAttachedServer() {
+      return attachedServer;
+   }
 
-    public String getCreator() {
-        return creator;
-    }
+   public String getCreator() {
+      return creator;
+   }
 
-    public double getSize() {
-        return size;
-    }
+   public double getSize() {
+      return size;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        VDisk that = VDisk.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      VDisk that = VDisk.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("attachedServer", attachedServer)
-                .add("creator", creator).add("size", size).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("attachedServer", attachedServer)
+            .add("creator", creator).add("size", size).toString();
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VDiskStatus.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VDiskStatus.java
index cc44594..c0ad812 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VDiskStatus.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VDiskStatus.java
@@ -18,12 +18,12 @@
  */
 package org.jclouds.fujitsu.fgcp.domain;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import javax.xml.bind.annotation.XmlRootElement;
 
 import com.google.common.base.CaseFormat;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 /**
  * Possible statuses of an attachable virtual disk.
  * 
@@ -32,24 +32,24 @@
 @XmlRootElement(name = "vdiskStatus")
 public enum VDiskStatus {
 
-    NORMAL, BACKUP_ING, DEPLOYING, DETACHING, ATTACHING, RESTORING, ERROR, UNRECOGNIZED;
+   NORMAL, BACKUP_ING, DEPLOYING, DETACHING, ATTACHING, RESTORING, ERROR, UNRECOGNIZED;
 
-    public String value() {
-        return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
-    }
+   public String value() {
+      return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
+   }
 
-    @Override
-    public String toString() {
-        return value();
-    }
+   @Override
+   public String toString() {
+      return value();
+   }
 
-    public static VDiskStatus fromValue(String status) {
-        try {
-            return valueOf(CaseFormat.UPPER_CAMEL
-                    .to(CaseFormat.UPPER_UNDERSCORE,
-                            checkNotNull(status, "status")));
-        } catch (IllegalArgumentException e) {
-            return UNRECOGNIZED;
-        }
-    }
+   public static VDiskStatus fromValue(String status) {
+      try {
+         return valueOf(CaseFormat.UPPER_CAMEL
+               .to(CaseFormat.UPPER_UNDERSCORE,
+                     checkNotNull(status, "status")));
+      } catch (IllegalArgumentException e) {
+         return UNRECOGNIZED;
+      }
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VNIC.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VNIC.java
index 6fbf077..9091384 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VNIC.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VNIC.java
@@ -29,45 +29,45 @@
  */
 @XmlRootElement(name = "vnic")
 public class VNIC {
-    private String networkId;
+   private String networkId;
 
-    private String privateIp;
+   private String privateIp;
 
-    private int nicNo;
+   private int nicNo;
 
-    public String getNetworkId() {
-        return networkId;
-    }
+   public String getNetworkId() {
+      return networkId;
+   }
 
-    public String getPrivateIp() {
-        return privateIp;
-    }
+   public String getPrivateIp() {
+      return privateIp;
+   }
 
-    public int getNicNo() {
-        return nicNo;
-    }
+   public int getNicNo() {
+      return nicNo;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(networkId);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(networkId);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        VNIC that = VNIC.class.cast(obj);
-        return Objects.equal(this.networkId, that.networkId);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      VNIC that = VNIC.class.cast(obj);
+      return Objects.equal(this.networkId, that.networkId);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues()
-                .add("networkId", networkId).add("privateIp", privateIp)
-                .add("nicNo", nicNo).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues()
+            .add("networkId", networkId).add("privateIp", privateIp)
+            .add("nicNo", nicNo).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VNet.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VNet.java
index 77210c1..99de06c 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VNet.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VNet.java
@@ -30,32 +30,32 @@
 @XmlRootElement(name = "vnet")
 public class VNet {
 
-    private String networkId;
+   private String networkId;
 
-    public String getNetworkId() {
-        return networkId;
-    }
+   public String getNetworkId() {
+      return networkId;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(networkId);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(networkId);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        VNet that = VNet.class.cast(obj);
-        return Objects.equal(this.networkId, that.networkId);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      VNet that = VNet.class.cast(obj);
+      return Objects.equal(this.networkId, that.networkId);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).add("networkId", networkId)
-                .toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).add("networkId", networkId)
+            .toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServer.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServer.java
index b3db299..9db887a 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServer.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServer.java
@@ -28,57 +28,57 @@
  * @author Dies Koper
  */
 public class VServer {
-    @XmlElement(name = "vserverId")
-    protected String id;
-    @XmlElement(name = "vserverName")
-    protected String name;
-    @XmlElement(name = "vserverType")
-    protected String type;
-    protected String diskimageId;
-    protected String creator;
+   @XmlElement(name = "vserverId")
+   protected String id;
+   @XmlElement(name = "vserverName")
+   protected String name;
+   @XmlElement(name = "vserverType")
+   protected String type;
+   protected String diskimageId;
+   protected String creator;
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public String getName() {
-        return name;
-    }
+   public String getName() {
+      return name;
+   }
 
-    public String getType() {
-        return type;
-    }
+   public String getType() {
+      return type;
+   }
 
-    public String getDiskimageId() {
-        return diskimageId;
-    }
+   public String getDiskimageId() {
+      return diskimageId;
+   }
 
-    public String getCreator() {
-        return creator;
-    }
+   public String getCreator() {
+      return creator;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        VServer that = VServer.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      VServer that = VServer.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("type", type).add("creator", creator)
-                .add("diskimageId", diskimageId).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("type", type).add("creator", creator)
+            .add("diskimageId", diskimageId).toString();
+   }
 
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerStatus.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerStatus.java
index 8576538..1df5ce0 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerStatus.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerStatus.java
@@ -18,12 +18,12 @@
  */
 package org.jclouds.fujitsu.fgcp.domain;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import javax.xml.bind.annotation.XmlRootElement;
 
 import com.google.common.base.CaseFormat;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 /**
  * Possible statuses of a virtual server.
  * 
@@ -31,24 +31,24 @@
  */
 @XmlRootElement(name = "vserverStatus")
 public enum VServerStatus {
-    DEPLOYING, RUNNING, STOPPING, STOPPED, STARTING, FAILOVER, UNEXPECTED_STOP, RESTORING, BACKUP_ING, ERROR, START_ERROR, STOP_ERROR, CHANGE_TYPE, REGISTERING, UNRECOGNIZED;
+   DEPLOYING, RUNNING, STOPPING, STOPPED, STARTING, FAILOVER, UNEXPECTED_STOP, RESTORING, BACKUP_ING, ERROR, START_ERROR, STOP_ERROR, CHANGE_TYPE, REGISTERING, UNRECOGNIZED;
 
-    public String value() {
-        return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
-    }
+   public String value() {
+      return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
+   }
 
-    @Override
-    public String toString() {
-        return value();
-    }
+   @Override
+   public String toString() {
+      return value();
+   }
 
-    public static VServerStatus fromValue(String status) {
-        try {
-            return valueOf(CaseFormat.UPPER_CAMEL
-                    .to(CaseFormat.UPPER_UNDERSCORE,
-                            checkNotNull(status, "status")));
-        } catch (IllegalArgumentException e) {
-            return UNRECOGNIZED;
-        }
-    }
+   public static VServerStatus fromValue(String status) {
+      try {
+         return valueOf(CaseFormat.UPPER_CAMEL
+               .to(CaseFormat.UPPER_UNDERSCORE,
+                     checkNotNull(status, "status")));
+      } catch (IllegalArgumentException e) {
+         return UNRECOGNIZED;
+      }
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerWithDetails.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerWithDetails.java
index d9613a4..c969953 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerWithDetails.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerWithDetails.java
@@ -35,25 +35,25 @@
  */
 @XmlRootElement(name = "vserver")
 public class VServerWithDetails extends VServerWithVNICs {
-    @XmlElementWrapper(name = "vdisks")
-    @XmlElement(name = "vdisk")
-    protected Set<VDisk> vdisks = new LinkedHashSet<VDisk>();
-    protected Image image;
+   @XmlElementWrapper(name = "vdisks")
+   @XmlElement(name = "vdisk")
+   protected Set<VDisk> vdisks = new LinkedHashSet<VDisk>();
+   protected Image image;
 
-    public Set<VDisk> getVdisks() {
-        return vdisks == null ? ImmutableSet.<VDisk> of() : ImmutableSet
-                .copyOf(vdisks);
-    }
+   public Set<VDisk> getVdisks() {
+      return vdisks == null ? ImmutableSet.<VDisk> of() : ImmutableSet
+            .copyOf(vdisks);
+   }
 
-    public Image getImage() {
-        return image;
-    }
+   public Image getImage() {
+      return image;
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("type", type).add("creator", creator)
-                .add("diskimageId", diskimageId).add("vdisks", vdisks)
-                .add("vnics", vnics).add("image", image).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("type", type).add("creator", creator)
+            .add("diskimageId", diskimageId).add("vdisks", vdisks)
+            .add("vnics", vnics).add("image", image).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerWithVNICs.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerWithVNICs.java
index 3117241..8e46a1d 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerWithVNICs.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VServerWithVNICs.java
@@ -11,19 +11,19 @@
 
 public class VServerWithVNICs extends VServer {
 
-    @XmlElementWrapper(name = "vnics")
-    @XmlElement(name = "vnic")
-    protected Set<VNIC> vnics = new LinkedHashSet<VNIC>();
+   @XmlElementWrapper(name = "vnics")
+   @XmlElement(name = "vnic")
+   protected Set<VNIC> vnics = new LinkedHashSet<VNIC>();
 
-    public Set<VNIC> getVnics() {
-        return vnics == null ? ImmutableSet.<VNIC> of() : ImmutableSet
-                .copyOf(vnics);
-    }
+   public Set<VNIC> getVnics() {
+      return vnics == null ? ImmutableSet.<VNIC> of() : ImmutableSet
+            .copyOf(vnics);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("type", type).add("creator", creator)
-                .add("diskimageId", diskimageId).add("vnics", vnics).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("type", type).add("creator", creator)
+            .add("diskimageId", diskimageId).add("vnics", vnics).toString();
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystem.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystem.java
index ae86034..30f51de 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystem.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystem.java
@@ -28,57 +28,57 @@
  * @author Dies Koper
  */
 public class VSystem {
-    @XmlElement(name = "vsysId")
-    protected String id;
-    @XmlElement(name = "vsysName")
-    protected String name;
-    protected String creator;
-    @XmlElement(name = "baseDescriptor")
-    protected String template;
-    protected String description;
+   @XmlElement(name = "vsysId")
+   protected String id;
+   @XmlElement(name = "vsysName")
+   protected String name;
+   protected String creator;
+   @XmlElement(name = "baseDescriptor")
+   protected String template;
+   protected String description;
 
-    public String getId() {
-        return id;
-    }
+   public String getId() {
+      return id;
+   }
 
-    public String getName() {
-        return name;
-    }
+   public String getName() {
+      return name;
+   }
 
-    public String getCreator() {
-        return creator;
-    }
+   public String getCreator() {
+      return creator;
+   }
 
-    public String getTemplate() {
-        return template;
-    }
+   public String getTemplate() {
+      return template;
+   }
 
-    public String getDescription() {
-        return description;
-    }
+   public String getDescription() {
+      return description;
+   }
 
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        VSystem that = VSystem.class.cast(obj);
-        return Objects.equal(this.id, that.id);
-    }
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      VSystem that = VSystem.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("creator", creator)
-                .add("template", template).add("description", description)
-                .toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("creator", creator)
+            .add("template", template).add("description", description)
+            .toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemDescriptor.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemDescriptor.java
index 46f448a..31a7a7e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemDescriptor.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemDescriptor.java
@@ -34,71 +34,71 @@
  */
 @XmlRootElement(name = "vsysdescriptor")
 public class VSystemDescriptor {
-    @XmlElement(name = "vsysdescriptorId")
-    private String id;
+   @XmlElement(name = "vsysdescriptorId")
+   private String id;
 
-    @XmlElement(name = "vsysdescriptorName")
-    private String name;
+   @XmlElement(name = "vsysdescriptorName")
+   private String name;
 
-    private String creatorName;
+   private String creatorName;
 
-    private String registrant;
+   private String registrant;
 
-    private String description;
+   private String description;
 
-    private String keyword;
+   private String keyword;
 
-    @XmlElementWrapper(name = "vservers")
-    @XmlElement(name = "vserver")
-    private Set<VServerWithDetails> servers = new LinkedHashSet<VServerWithDetails>();
+   @XmlElementWrapper(name = "vservers")
+   @XmlElement(name = "vserver")
+   private Set<VServerWithDetails> servers = new LinkedHashSet<VServerWithDetails>();
 
-    /**
-     * @return the id
-     */
-    public String getId() {
-        return id;
-    }
+   /**
+    * @return the id
+    */
+   public String getId() {
+      return id;
+   }
 
-    /**
-     * @return the name
-     */
-    public String getName() {
-        return name;
-    }
+   /**
+    * @return the name
+    */
+   public String getName() {
+      return name;
+   }
 
-    /**
-     * @return the creatorName
-     */
-    public String getCreatorName() {
-        return creatorName;
-    }
+   /**
+    * @return the creatorName
+    */
+   public String getCreatorName() {
+      return creatorName;
+   }
 
-    /**
-     * @return the registrant
-     */
-    public String getRegistrant() {
-        return registrant;
-    }
+   /**
+    * @return the registrant
+    */
+   public String getRegistrant() {
+      return registrant;
+   }
 
-    /**
-     * @return the description
-     */
-    public String getDescription() {
-        return description;
-    }
+   /**
+    * @return the description
+    */
+   public String getDescription() {
+      return description;
+   }
 
-    /**
-     * @return the keyword
-     */
-    public String getKeyword() {
-        return keyword;
-    }
+   /**
+    * @return the keyword
+    */
+   public String getKeyword() {
+      return keyword;
+   }
 
-    /**
-     * @return the servers
-     */
-    public Set<VServerWithDetails> getServers() {
-        return servers == null ? ImmutableSet.<VServerWithDetails> of()
-                : ImmutableSet.copyOf(servers);
-    }
+   /**
+    * @return the servers
+    */
+   public Set<VServerWithDetails> getServers() {
+      return servers == null ? ImmutableSet.<VServerWithDetails> of()
+            : ImmutableSet.copyOf(servers);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemStatus.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemStatus.java
index 58e6e7a..1668b29 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemStatus.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemStatus.java
@@ -18,12 +18,12 @@
  */
 package org.jclouds.fujitsu.fgcp.domain;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import javax.xml.bind.annotation.XmlRootElement;
 
 import com.google.common.base.CaseFormat;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 /**
  * Possible statuses of a virtual system.
  * 
@@ -31,24 +31,24 @@
  */
 @XmlRootElement(name = "vsysStatus")
 public enum VSystemStatus {
-    NORMAL, RECONFIG_ING, DEPLOYING, ERROR, UNRECOGNIZED;
+   NORMAL, RECONFIG_ING, DEPLOYING, ERROR, UNRECOGNIZED;
 
-    public String value() {
-        return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
-    }
+   public String value() {
+      return (CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name()));
+   }
 
-    @Override
-    public String toString() {
-        return value();
-    }
+   @Override
+   public String toString() {
+      return value();
+   }
 
-    public static VSystemStatus fromValue(String status) {
-        try {
-            return valueOf(CaseFormat.UPPER_CAMEL
-                    .to(CaseFormat.UPPER_UNDERSCORE,
-                            checkNotNull(status, "status")));
-        } catch (IllegalArgumentException e) {
-            return UNRECOGNIZED;
-        }
-    }
+   public static VSystemStatus fromValue(String status) {
+      try {
+         return valueOf(CaseFormat.UPPER_CAMEL
+               .to(CaseFormat.UPPER_UNDERSCORE,
+                     checkNotNull(status, "status")));
+      } catch (IllegalArgumentException e) {
+         return UNRECOGNIZED;
+      }
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemWithDetails.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemWithDetails.java
index 1683988..7ae51fd 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemWithDetails.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/VSystemWithDetails.java
@@ -36,45 +36,45 @@
  */
 @XmlRootElement(name = "vsys")
 public class VSystemWithDetails extends VSystem {
-    @XmlElementWrapper(name = "vservers")
-    @XmlElement(name = "vserver")
-    private Set<VServerWithVNICs> servers = new LinkedHashSet<VServerWithVNICs>();
-    @XmlElementWrapper(name = "vdisks")
-    @XmlElement(name = "vdisk")
-    private Set<VDisk> disks = new LinkedHashSet<VDisk>();
-    @XmlElementWrapper(name = "publicips")
-    @XmlElement(name = "publicip")
-    private Set<PublicIP> publicips = new LinkedHashSet<PublicIP>();
-    @XmlElementWrapper(name = "vnets")
-    @XmlElement(name = "vnet")
-    private Set<VNet> networks = new LinkedHashSet<VNet>();
+   @XmlElementWrapper(name = "vservers")
+   @XmlElement(name = "vserver")
+   private Set<VServerWithVNICs> servers = new LinkedHashSet<VServerWithVNICs>();
+   @XmlElementWrapper(name = "vdisks")
+   @XmlElement(name = "vdisk")
+   private Set<VDisk> disks = new LinkedHashSet<VDisk>();
+   @XmlElementWrapper(name = "publicips")
+   @XmlElement(name = "publicip")
+   private Set<PublicIP> publicips = new LinkedHashSet<PublicIP>();
+   @XmlElementWrapper(name = "vnets")
+   @XmlElement(name = "vnet")
+   private Set<VNet> networks = new LinkedHashSet<VNet>();
 
-    public Set<VServerWithVNICs> getServers() {
-        return servers == null ? ImmutableSet.<VServerWithVNICs> of() : ImmutableSet
-                .copyOf(servers);
-    }
+   public Set<VServerWithVNICs> getServers() {
+      return servers == null ? ImmutableSet.<VServerWithVNICs> of() : ImmutableSet
+            .copyOf(servers);
+   }
 
-    public Set<VDisk> getDisks() {
-        return disks == null ? ImmutableSet.<VDisk> of() : ImmutableSet
-                .copyOf(disks);
-    }
+   public Set<VDisk> getDisks() {
+      return disks == null ? ImmutableSet.<VDisk> of() : ImmutableSet
+            .copyOf(disks);
+   }
 
-    public Set<PublicIP> getPublicips() {
-        return publicips == null ? ImmutableSet.<PublicIP> of() : ImmutableSet
-                .copyOf(publicips);
-    }
+   public Set<PublicIP> getPublicips() {
+      return publicips == null ? ImmutableSet.<PublicIP> of() : ImmutableSet
+            .copyOf(publicips);
+   }
 
-    public Set<VNet> getNetworks() {
-        return networks == null ? ImmutableSet.<VNet> of() : ImmutableSet
-                .copyOf(networks);
-    }
+   public Set<VNet> getNetworks() {
+      return networks == null ? ImmutableSet.<VNet> of() : ImmutableSet
+            .copyOf(networks);
+   }
 
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(this).omitNullValues().add("id", id)
-                .add("name", name).add("creator", creator)
-                .add("template", template).add("description", description)
-                .add("disks", disks).add("networks", networks)
-                .add("publicips", publicips).add("servers", servers).toString();
-    }
+   @Override
+   public String toString() {
+      return Objects.toStringHelper(this).omitNullValues().add("id", id)
+            .add("name", name).add("creator", creator)
+            .add("template", template).add("description", description)
+            .add("disks", disks).add("networks", networks)
+            .add("publicips", publicips).add("servers", servers).toString();
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/package-info.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/package-info.java
index 4f79fc1..4c2494a 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/package-info.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/domain/package-info.java
@@ -20,7 +20,7 @@
 @XmlAccessorType(XmlAccessType.FIELD)
 package org.jclouds.fujitsu.fgcp.domain;
 
-import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlSchema;
 
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/filters/RequestAuthenticator.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/filters/RequestAuthenticator.java
index 9fecf69..4cf2340 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/filters/RequestAuthenticator.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/filters/RequestAuthenticator.java
@@ -42,7 +42,6 @@
 import javax.ws.rs.core.UriBuilder;
 
 import org.jclouds.Constants;
-import org.jclouds.crypto.CryptoStreams;
 import org.jclouds.date.TimeStamp;
 import org.jclouds.encryption.internal.Base64;
 import org.jclouds.fujitsu.fgcp.reference.RequestParameters;
@@ -69,174 +68,174 @@
 @Singleton
 public class RequestAuthenticator implements HttpRequestFilter, RequestSigner {
 
-    @Resource
-    @Named(Constants.LOGGER_SIGNATURE)
-    private Logger signatureLog = Logger.NULL;
+   @Resource
+   @Named(Constants.LOGGER_SIGNATURE)
+   private Logger signatureLog = Logger.NULL;
 
-    final Provider<Calendar> calendarProvider;
-    final Signature signer;
-    final Provider<UriBuilder> builder;
-    final String apiVersion;
+   final Provider<Calendar> calendarProvider;
+   final Signature signer;
+   final Provider<UriBuilder> builder;
+   final String apiVersion;
 
-    public String signatureVersion = "1.0";
-    public String signatureMethod = "SHA1withRSA";
+   public String signatureVersion = "1.0";
+   public String signatureMethod = "SHA1withRSA";
 
-    private HttpUtils utils;
+   private HttpUtils utils;
 
-    @Inject
-    public RequestAuthenticator(@TimeStamp Provider<Calendar> calendarProvider,
-            Provider<KeyStore> keyStoreProvider,
-            @Credential String keyPassword, Provider<UriBuilder> builder,
-            HttpUtils utils, SignatureWire signatureWire,
-            @ApiVersion String apiVersion) throws NoSuchAlgorithmException,
-            InvalidKeyException, KeyStoreException, UnrecoverableKeyException {
-        this.calendarProvider = checkNotNull(calendarProvider);
-        this.builder = checkNotNull(builder);
-        this.utils = checkNotNull(utils, "utils");
-        this.apiVersion = checkNotNull(apiVersion, "apiVersion");
+   @Inject
+   public RequestAuthenticator(@TimeStamp Provider<Calendar> calendarProvider,
+         Provider<KeyStore> keyStoreProvider,
+         @Credential String keyPassword, Provider<UriBuilder> builder,
+         HttpUtils utils, SignatureWire signatureWire,
+         @ApiVersion String apiVersion) throws NoSuchAlgorithmException,
+         InvalidKeyException, KeyStoreException, UnrecoverableKeyException {
+      this.calendarProvider = checkNotNull(calendarProvider);
+      this.builder = checkNotNull(builder);
+      this.utils = checkNotNull(utils, "utils");
+      this.apiVersion = checkNotNull(apiVersion, "apiVersion");
 
-        signer = Signature.getInstance(signatureMethod);
+      signer = Signature.getInstance(signatureMethod);
 
-        KeyStore keyStore = checkNotNull(keyStoreProvider).get();
-        String alias = keyStore.aliases().nextElement(); // there should be only
-                                                         // one private key
-        PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias,
-                keyPassword.toCharArray());
+      KeyStore keyStore = checkNotNull(keyStoreProvider).get();
+      String alias = keyStore.aliases().nextElement(); // there should be only
+                                           // one private key
+      PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias,
+            keyPassword.toCharArray());
 
-        signer.initSign(privateKey);
-    }
+      signer.initSign(privateKey);
+   }
 
-    public HttpRequest filter(HttpRequest request) throws HttpException {
-        checkNotNull(request, "request must be present");
+   public HttpRequest filter(HttpRequest request) throws HttpException {
+      checkNotNull(request, "request must be present");
 
-        utils.logRequest(signatureLog, request, ">>");
+      utils.logRequest(signatureLog, request, ">>");
 
-        // create accesskeyid
-        String accessKeyId = createStringToSign(request);
-        String signature = sign(accessKeyId);
+      // create accesskeyid
+      String accessKeyId = createStringToSign(request);
+      String signature = sign(accessKeyId);
 
-        // leaving this in for now for reference in case I need it for multipart
-        // POSTs
-        // add parameters. Note that in case of a GET, url escaping is required
-        /*
-         * Multimap<String, String> decodedParams = null; if
-         * (HttpMethod.GET.equals(request.getMethod())) { decodedParams =
-         * ModifyRequest.parseQueryToMap(request.getEndpoint().getRawQuery());
-         * 
-         * } else if (HttpMethod.POST.equals(request.getMethod())) {
-         * decodedParams =
-         * ModifyRequest.parseQueryToMap(request.getPayload().getRawContent()
-         * .toString()); }
-         * 
-         * checkNotNull(decodedParams, "no query params found");
-         * System.out.println("filter: request params before: " +
-         * decodedParams.toString()); addAuthenticationParams(decodedParams,
-         * accessKeyId, signature); addLocaleParam(decodedParams);
-         * System.out.println("filter: request params after : " +
-         * decodedParams.toString()); if (signatureWire.enabled())
-         * signatureWire.output(decodedParams);
-         * 
-         * 
-         * request = setPayload(request, decodedParams);
-         */
-        // only "en" and "ja" are allowed
-        String lang = Locale.JAPANESE.getLanguage().equals(
-                Locale.getDefault().getLanguage()) ? Locale.JAPANESE
-                .getLanguage() : Locale.ENGLISH.getLanguage();
+      // leaving this in for now for reference in case I need it for multipart
+      // POSTs
+      // add parameters. Note that in case of a GET, url escaping is required
+      /*
+       * Multimap<String, String> decodedParams = null; if
+       * (HttpMethod.GET.equals(request.getMethod())) { decodedParams =
+       * ModifyRequest.parseQueryToMap(request.getEndpoint().getRawQuery());
+       * 
+       * } else if (HttpMethod.POST.equals(request.getMethod())) {
+       * decodedParams =
+       * ModifyRequest.parseQueryToMap(request.getPayload().getRawContent()
+       * .toString()); }
+       * 
+       * checkNotNull(decodedParams, "no query params found");
+       * System.out.println("filter: request params before: " +
+       * decodedParams.toString()); addAuthenticationParams(decodedParams,
+       * accessKeyId, signature); addLocaleParam(decodedParams);
+       * System.out.println("filter: request params after : " +
+       * decodedParams.toString()); if (signatureWire.enabled())
+       * signatureWire.output(decodedParams);
+       * 
+       * 
+       * request = setPayload(request, decodedParams);
+       */
+      // only "en" and "ja" are allowed
+      String lang = Locale.JAPANESE.getLanguage().equals(
+            Locale.getDefault().getLanguage()) ? Locale.JAPANESE
+            .getLanguage() : Locale.ENGLISH.getLanguage();
 
-        if (HttpMethod.GET.equals(request.getMethod())) {
-            Multimap<String, String> decodedParams = Queries
-                    .parseQueryToMap(request.getEndpoint().getRawQuery());
+      if (HttpMethod.GET.equals(request.getMethod())) {
+         Multimap<String, String> decodedParams = Queries
+               .parseQueryToMap(request.getEndpoint().getRawQuery());
 
-            if (!decodedParams.containsKey(RequestParameters.VERSION)) {
-                decodedParams.put(RequestParameters.VERSION, apiVersion);
-            }
-            decodedParams.put(RequestParameters.LOCALE, lang);
-            decodedParams.put(RequestParameters.ACCESS_KEY_ID, accessKeyId);
-            decodedParams.put(RequestParameters.SIGNATURE, signature);
-            request = request.toBuilder().replaceQueryParams(decodedParams)
-                    .build();
-        } else {
+         if (!decodedParams.containsKey(RequestParameters.VERSION)) {
+            decodedParams.put(RequestParameters.VERSION, apiVersion);
+         }
+         decodedParams.put(RequestParameters.LOCALE, lang);
+         decodedParams.put(RequestParameters.ACCESS_KEY_ID, accessKeyId);
+         decodedParams.put(RequestParameters.SIGNATURE, signature);
+         request = request.toBuilder().replaceQueryParams(decodedParams)
+               .build();
+      } else {
 
-            String payload = request.getPayload().getRawContent().toString();
-            payload = createXmlElementWithValue(payload,
-                    RequestParameters.VERSION, apiVersion);
-            payload = createXmlElementWithValue(payload,
-                    RequestParameters.LOCALE, lang);
-            payload = createXmlElementWithValue(payload,
-                    RequestParameters.ACCESS_KEY_ID, accessKeyId);
-            payload = createXmlElementWithValue(payload,
-                    RequestParameters.SIGNATURE, signature);
+         String payload = request.getPayload().getRawContent().toString();
+         payload = createXmlElementWithValue(payload,
+               RequestParameters.VERSION, apiVersion);
+         payload = createXmlElementWithValue(payload,
+               RequestParameters.LOCALE, lang);
+         payload = createXmlElementWithValue(payload,
+               RequestParameters.ACCESS_KEY_ID, accessKeyId);
+         payload = createXmlElementWithValue(payload,
+               RequestParameters.SIGNATURE, signature);
 
-            // ensure there are no other query params left
-            request.setPayload(payload);
-            request.getPayload().getContentMetadata()
-                    .setContentType(MediaType.TEXT_XML);
-        }
+         // ensure there are no other query params left
+         request.setPayload(payload);
+         request.getPayload().getContentMetadata()
+               .setContentType(MediaType.TEXT_XML);
+      }
 
-        // may need to do this elsewhere (see ConvertToGaeRequest)
-        HttpRequest filteredRequest = request.toBuilder()
-                .replaceHeader(HttpHeaders.USER_AGENT, "OViSS-API-CLIENT")
-                .build();
+      // may need to do this elsewhere (see ConvertToGaeRequest)
+      HttpRequest filteredRequest = request.toBuilder()
+            .replaceHeader(HttpHeaders.USER_AGENT, "OViSS-API-CLIENT")
+            .build();
 
-        utils.logRequest(signatureLog, filteredRequest, ">>->");
+      utils.logRequest(signatureLog, filteredRequest, ">>->");
 
-        return filteredRequest;
-    }
+      return filteredRequest;
+   }
 
-    String createXmlElementWithValue(String payload, String tag, String value) {
-        String startTag = String.format("<%s>", tag);
-        String endTag = String.format("</%s>", tag);
+   String createXmlElementWithValue(String payload, String tag, String value) {
+      String startTag = String.format("<%s>", tag);
+      String endTag = String.format("</%s>", tag);
 
-        return payload.replace(startTag + endTag, startTag + value + endTag);
-    }
+      return payload.replace(startTag + endTag, startTag + value + endTag);
+   }
 
-    /*
-     * HttpRequest setPayload(HttpRequest request, Multimap<String, String>
-     * decodedParams) {
-     * request.setPayload(ModifyRequest.makeQueryLine(decodedParams, null)); //
-     * request.getPayload().getContentMetadata().setContentType(
-     * "application/x-www-form-urlencoded"); return request; }
-     */
+   /*
+    * HttpRequest setPayload(HttpRequest request, Multimap<String, String>
+    * decodedParams) {
+    * request.setPayload(ModifyRequest.makeQueryLine(decodedParams, null)); //
+    * request.getPayload().getContentMetadata().setContentType(
+    * "application/x-www-form-urlencoded"); return request; }
+    */
 
-    @VisibleForTesting
-    public String sign(String stringToSign) {
-        String signed;
+   @VisibleForTesting
+   public String sign(String stringToSign) {
+      String signed;
 
-        try {
-            signer.update(stringToSign.getBytes("UTF-8"));
-            signed = Base64.encodeBytes(signer.sign()).replace("\n", "\r\n");
-//            signed = CryptoStreams.base64(signer.sign());
-        } catch (Exception e) {
-            throw new HttpException("error signing request", e);
-        }
-        // if (signatureWire.enabled())
-        // signatureWire.input(Strings2.toInputStream(signed));
+      try {
+         signer.update(stringToSign.getBytes("UTF-8"));
+         signed = Base64.encodeBytes(signer.sign()).replace("\n", "\r\n");
+//         signed = CryptoStreams.base64(signer.sign());
+      } catch (Exception e) {
+         throw new HttpException("error signing request", e);
+      }
+      // if (signatureWire.enabled())
+      // signatureWire.input(Strings2.toInputStream(signed));
 
-        return signed;
-    }
+      return signed;
+   }
 
-    @VisibleForTesting
-    public String generateAccessKeyId() {
-        Calendar cal = calendarProvider.get();
-        String timezone = cal.getTimeZone().getDisplayName(Locale.ENGLISH);
-        String expires = String.valueOf(cal.getTime().getTime());
+   @VisibleForTesting
+   public String generateAccessKeyId() {
+      Calendar cal = calendarProvider.get();
+      String timezone = cal.getTimeZone().getDisplayName(Locale.ENGLISH);
+      String expires = String.valueOf(cal.getTime().getTime());
 
-        String signatureData = String.format("%s&%s&%s&%s", timezone, expires,
-                signatureVersion, signatureMethod);
-        try {
-            String accessKeyId = Base64.encodeBytes(signatureData.getBytes("UTF-8"));
-            return accessKeyId.replace("\n", "\r\n");
-//            return CryptoStreams.base64(signatureData.getBytes("UTF-8")).;
-        } catch (UnsupportedEncodingException e) {
-            throw new RuntimeException(e); // should never happen as
-                                           // signatureData contains only ASCII
-        }
-    }
+      String signatureData = String.format("%s&%s&%s&%s", timezone, expires,
+            signatureVersion, signatureMethod);
+      try {
+         String accessKeyId = Base64.encodeBytes(signatureData.getBytes("UTF-8"));
+         return accessKeyId.replace("\n", "\r\n");
+//         return CryptoStreams.base64(signatureData.getBytes("UTF-8")).;
+      } catch (UnsupportedEncodingException e) {
+         throw new RuntimeException(e); // should never happen as
+                                 // signatureData contains only ASCII
+      }
+   }
 
-    @Override
-    public String createStringToSign(HttpRequest input) {
-        return generateAccessKeyId();
-    }
+   @Override
+   public String createStringToSign(HttpRequest input) {
+      return generateAccessKeyId();
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPRetryIfNotProxyAuthenticationFailureHandler.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPRetryIfNotProxyAuthenticationFailureHandler.java
index 0104aaf..9d4c05d 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPRetryIfNotProxyAuthenticationFailureHandler.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/handlers/FGCPRetryIfNotProxyAuthenticationFailureHandler.java
@@ -18,13 +18,14 @@
  */
 package org.jclouds.fujitsu.fgcp.handlers;
 
-import com.google.inject.Singleton;
+import javax.annotation.Resource;
+
 import org.jclouds.http.HttpCommand;
 import org.jclouds.http.HttpResponse;
 import org.jclouds.http.HttpRetryHandler;
 import org.jclouds.logging.Logger;
 
-import javax.annotation.Resource;
+import com.google.inject.Singleton;
 
 /**
  * Created by IntelliJ IDEA.
@@ -33,15 +34,15 @@
  */
 @Singleton
 public class FGCPRetryIfNotProxyAuthenticationFailureHandler implements
-        HttpRetryHandler {
-    @Resource
-    protected Logger logger = Logger.NULL;
+      HttpRetryHandler {
+   @Resource
+   protected Logger logger = Logger.NULL;
 
-    @Override
-    public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
-        int statusCode = response.getStatusCode();
-        System.out.println("Response status code: " + statusCode);
-        logger.error("StatusCode", statusCode);
-        return true;
-    }
+   @Override
+   public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
+      int statusCode = response.getStatusCode();
+      System.out.println("Response status code: " + statusCode);
+      logger.error("StatusCode", statusCode);
+      return true;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/http/SSLContextWithKeysSupplier.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/http/SSLContextWithKeysSupplier.java
index c0e2019..38974e3 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/http/SSLContextWithKeysSupplier.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/http/SSLContextWithKeysSupplier.java
@@ -45,27 +45,27 @@
  */
 @Singleton
 public class SSLContextWithKeysSupplier implements Supplier<SSLContext> {
-    private SSLContext sc;
+   private SSLContext sc;
 
-    @Inject
-    SSLContextWithKeysSupplier(KeyStore keyStore,
-            @Credential String keyStorePassword, HttpUtils utils,
-            TrustAllCerts trustAllCerts) throws NoSuchAlgorithmException,
-            KeyStoreException, UnrecoverableKeyException,
-            KeyManagementException {
+   @Inject
+   SSLContextWithKeysSupplier(KeyStore keyStore,
+         @Credential String keyStorePassword, HttpUtils utils,
+         TrustAllCerts trustAllCerts) throws NoSuchAlgorithmException,
+         KeyStoreException, UnrecoverableKeyException,
+         KeyManagementException {
 
-        TrustManager[] trustManager = null;
-        if (utils.trustAllCerts()) {
-            trustManager = new TrustManager[] { trustAllCerts };
-        }
-        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
-        kmf.init(keyStore, keyStorePassword.toCharArray());
-        sc = SSLContext.getInstance("TLS");
-        sc.init(kmf.getKeyManagers(), trustManager, new SecureRandom());
-    }
+      TrustManager[] trustManager = null;
+      if (utils.trustAllCerts()) {
+         trustManager = new TrustManager[] { trustAllCerts };
+      }
+      KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+      kmf.init(keyStore, keyStorePassword.toCharArray());
+      sc = SSLContext.getInstance("TLS");
+      sc.init(kmf.getKeyManagers(), trustManager, new SecureRandom());
+   }
 
-    @Override
-    public SSLContext get() {
-        return sc;
-    }
+   @Override
+   public SSLContext get() {
+      return sc;
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/location/SystemAndNetworkSegmentToLocationSupplier.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/location/SystemAndNetworkSegmentToLocationSupplier.java
index 569d3ae..476db4c 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/location/SystemAndNetworkSegmentToLocationSupplier.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/location/SystemAndNetworkSegmentToLocationSupplier.java
@@ -66,55 +66,55 @@
  */
 @Singleton
 public class SystemAndNetworkSegmentToLocationSupplier implements
-        LocationsSupplier {
+      LocationsSupplier {
 
-    private final RegionToProviderOrJustProvider regionProvider;
-    private FGCPAsyncApi api;
+   private final RegionToProviderOrJustProvider regionProvider;
+   private FGCPAsyncApi api;
 
-    @Inject
-    SystemAndNetworkSegmentToLocationSupplier(
-            RegionToProviderOrJustProvider regionProvider, FGCPAsyncApi api) {
-        this.regionProvider = checkNotNull(regionProvider,
-                "regionToProviderOrJustProvider");
-        this.api = checkNotNull(api, "api");
-    }
+   @Inject
+   SystemAndNetworkSegmentToLocationSupplier(
+         RegionToProviderOrJustProvider regionProvider, FGCPAsyncApi api) {
+      this.regionProvider = checkNotNull(regionProvider,
+            "regionToProviderOrJustProvider");
+      this.api = checkNotNull(api, "api");
+   }
 
-    @Override
-    public Set<Location> get() {
-        Builder<Location> locations = ImmutableSet.builder();
-        try {
-            List<ListenableFuture<VSystemWithDetails>> futures = new ArrayList<ListenableFuture<VSystemWithDetails>>();
-            for (VSystem system : api.getVirtualDCApi().listVirtualSystems()
-                    .get()) {
+   @Override
+   public Set<Location> get() {
+      Builder<Location> locations = ImmutableSet.builder();
+      try {
+         List<ListenableFuture<VSystemWithDetails>> futures = new ArrayList<ListenableFuture<VSystemWithDetails>>();
+         for (VSystem system : api.getVirtualDCApi().listVirtualSystems()
+               .get()) {
 
-                futures.add(api.getVirtualSystemApi()
-                        .getDetails(system.getId()));
+            futures.add(api.getVirtualSystemApi()
+                  .getDetails(system.getId()));
+         }
+         for (VSystemWithDetails system : Futures.successfulAsList(futures)
+               .get()) {
+
+            Location systemLocation = new LocationBuilder()
+                  .scope(LocationScope.SYSTEM)
+                  .parent(Iterables.getOnlyElement(regionProvider.get()))
+                  .description(system.getName()).id(system.getId())
+                  .build();
+
+            for (VNet net : system.getNetworks()) {
+
+               locations.add(new LocationBuilder()
+                     .scope(LocationScope.NETWORK)
+                     .parent(systemLocation)
+                     .description(
+                           net.getNetworkId().replaceFirst(
+                                 ".+(DMZ|SECURE.)", "\\1"))
+                     .id(net.getNetworkId()).build());
             }
-            for (VSystemWithDetails system : Futures.successfulAsList(futures)
-                    .get()) {
-
-                Location systemLocation = new LocationBuilder()
-                        .scope(LocationScope.SYSTEM)
-                        .parent(Iterables.getOnlyElement(regionProvider.get()))
-                        .description(system.getName()).id(system.getId())
-                        .build();
-
-                for (VNet net : system.getNetworks()) {
-
-                    locations.add(new LocationBuilder()
-                            .scope(LocationScope.NETWORK)
-                            .parent(systemLocation)
-                            .description(
-                                    net.getNetworkId().replaceFirst(
-                                            ".+(DMZ|SECURE.)", "\\1"))
-                            .id(net.getNetworkId()).build());
-                }
-            }
-        } catch (InterruptedException e) {
-            throw Throwables.propagate(e);
-        } catch (ExecutionException e) {
-            throw Throwables.propagate(e);
-        }
-        return locations.build();
-    }
+         }
+      } catch (InterruptedException e) {
+         throw Throwables.propagate(e);
+      } catch (ExecutionException e) {
+         throw Throwables.propagate(e);
+      }
+      return locations.build();
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/reference/RequestParameters.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/reference/RequestParameters.java
index d4870c5..784773c 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/reference/RequestParameters.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/reference/RequestParameters.java
@@ -25,57 +25,57 @@
  */
 public interface RequestParameters {
 
-    /**
-     * Indicates the action to perform. Example: ListVSYS
-     */
-    public static final String ACTION = "Action";
+   /**
+    * Indicates the action to perform. Example: ListVSYS
+    */
+   public static final String ACTION = "Action";
 
-    /**
-     * The API version to use. Example: 2011-01-31
-     */
-    public static final String VERSION = "Version";
+   /**
+    * The API version to use. Example: 2011-01-31
+    */
+   public static final String VERSION = "Version";
 
-    /**
-     * The locale to use. Example: en
-     */
-    public static final String LOCALE = "Locale";
+   /**
+    * The locale to use. Example: en
+    */
+   public static final String LOCALE = "Locale";
 
-    /**
-     * The Access Key ID for the request sender. This identifies the account
-     * which will be charged for usage of the service. The account with which
-     * the Access Key ID is associated must be signed up for FGCP, or requests
-     * will not be accepted. AKIADQKE4SARGYLE
-     */
-    public static final String ACCESS_KEY_ID = "AccessKeyId";
+   /**
+    * The Access Key ID for the request sender. This identifies the account
+    * which will be charged for usage of the service. The account with which
+    * the Access Key ID is associated must be signed up for FGCP, or requests
+    * will not be accepted. AKIADQKE4SARGYLE
+    */
+   public static final String ACCESS_KEY_ID = "AccessKeyId";
 
-    /**
-     * The date and time at which the request is signed, in the format
-     * YYYY-MM-DDThh:mm:ssZ. For more information, go to ISO 8601. Example:
-     * 2006-07-07T15:04:56Z
-     */
-    public static final String TIMESTAMP = "Timestamp";
+   /**
+    * The date and time at which the request is signed, in the format
+    * YYYY-MM-DDThh:mm:ssZ. For more information, go to ISO 8601. Example:
+    * 2006-07-07T15:04:56Z
+    */
+   public static final String TIMESTAMP = "Timestamp";
 
-    /**
-     * The date and time at which the signer included in the request expires, in
-     * the format YYYY-MM-DDThh:mm:ssZ. Example: 2006-07-07T15:04:56Z
-     */
-    public static final String EXPIRES = "Expires";
+   /**
+    * The date and time at which the signer included in the request expires, in
+    * the format YYYY-MM-DDThh:mm:ssZ. Example: 2006-07-07T15:04:56Z
+    */
+   public static final String EXPIRES = "Expires";
 
-    /**
-     * The request signer. For more information, go to the Amazon Elastic
-     * Compute Cloud Developer Guide. Example: Qnpl4Qk/7tINHzfXCiT7VbBatDA=
-     */
-    public static final String SIGNATURE = "Signature";
+   /**
+    * The request signer. For more information, go to the Amazon Elastic
+    * Compute Cloud Developer Guide. Example: Qnpl4Qk/7tINHzfXCiT7VbBatDA=
+    */
+   public static final String SIGNATURE = "Signature";
 
-    /**
-     * The hash algorithm you use to create the request signer. Valid value:
-     * SHA1withRSA.
-     */
-    public static final String SIGNATURE_METHOD = "SignatureMethod";
+   /**
+    * The hash algorithm you use to create the request signer. Valid value:
+    * SHA1withRSA.
+    */
+   public static final String SIGNATURE_METHOD = "SignatureMethod";
 
-    /**
-     * The signer version you use to sign the request. Set this value to 1.0.
-     * 
-     */
-    public static final String SIGNATURE_VERSION = "SignatureVersion";
+   /**
+    * The signer version you use to sign the request. Set this value to 1.0.
+    * 
+    */
+   public static final String SIGNATURE_VERSION = "SignatureVersion";
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskApi.java
index 2b4cbb6..ec0e455 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.fujitsu.fgcp.services;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -33,21 +32,21 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface AdditionalDiskApi {
 
-    VDiskStatus getStatus(String id);
+   VDiskStatus getStatus(String id);
 
-    VDisk get(String id);
+   VDisk get(String id);
 
-    void update(String id, String name, String value);
+   void update(String id, String name, String value);
 
-    void backup(String id);
+   void backup(String id);
 
-    void restore(String systemId, String backupId);
+   void restore(String systemId, String backupId);
 
-    void destroy(String id);
+   void destroy(String id);
 
-    void detach(String diskId, String serverId);
+   void detach(String diskId, String serverId);
 
-    void destroyBackup(String sysId, String backupId);
+   void destroyBackup(String sysId, String backupId);
 
-    // Set<> listBackups(String sysId);
+   // Set<> listBackups(String sysId);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskAsyncApi.java
index 440be5b..e377485 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskAsyncApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.fujitsu.fgcp.services;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.Consumes;
@@ -55,58 +54,58 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface AdditionalDiskAsyncApi {
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVDiskStatus")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VDiskStatus> getStatus(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVDiskStatus")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VDiskStatus> getStatus(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVDiskAttributes")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VDisk> get(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVDiskAttributes")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VDisk> get(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id);
 
-    @GET
-    @QueryParams(keys = "Action", values = "UpdateVDiskAttribute")
-    ListenableFuture<Void> update(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id,
-            @QueryParam("attributeName") String name,
-            @QueryParam("attributeValue") String value);
+   @GET
+   @QueryParams(keys = "Action", values = "UpdateVDiskAttribute")
+   ListenableFuture<Void> update(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id,
+         @QueryParam("attributeName") String name,
+         @QueryParam("attributeValue") String value);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "BackupVDisk")
-    ListenableFuture<Void> backup(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "BackupVDisk")
+   ListenableFuture<Void> backup(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "RestoreVDisk")
-    ListenableFuture<Void> restore(@QueryParam("vsysId") String systemId,
-            @QueryParam("backupId") String backupId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "RestoreVDisk")
+   ListenableFuture<Void> restore(@QueryParam("vsysId") String systemId,
+         @QueryParam("backupId") String backupId);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DestroyVDisk")
-    ListenableFuture<Void> destroy(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DestroyVDisk")
+   ListenableFuture<Void> destroy(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DetachVDisk")
-    ListenableFuture<Void> detach(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String diskId,
-            @QueryParam("vserverId") String serverId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DetachVDisk")
+   ListenableFuture<Void> detach(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vdiskId") String diskId,
+         @QueryParam("vserverId") String serverId);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DestroyVDiskBackup")
-    ListenableFuture<Void> destroyBackup(@QueryParam("vsysId") String sysId,
-            @QueryParam("backupId") String backupId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DestroyVDiskBackup")
+   ListenableFuture<Void> destroyBackup(@QueryParam("vsysId") String sysId,
+         @QueryParam("backupId") String backupId);
 
-    // Set<> listBackups(String sysId);
+   // Set<> listBackups(String sysId);
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerApi.java
index 274b1fb..82bb512 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerApi.java
@@ -36,38 +36,38 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface BuiltinServerApi {
 
-    void start(String id);
+   void start(String id);
 
-    void stop(String id);
+   void stop(String id);
 
-    void destroy(String id);
+   void destroy(String id);
 
-    void backup(String id);
+   void backup(String id);
 
-    void restore(String id, String backupId);
+   void restore(String id, String backupId);
 
-    Set<BuiltinServerBackup> listBackups(String id);
+   Set<BuiltinServerBackup> listBackups(String id);
 
-    void destroyBackup(String id, String backupId);
+   void destroyBackup(String id, String backupId);
 
-    BuiltinServer get(String id);
+   BuiltinServer get(String id);
 
-    void update(String id, String name, String value);
+   void update(String id, String name, String value);
 
-    BuiltinServerStatus getStatus(String id);
+   BuiltinServerStatus getStatus(String id);
 
-    BuiltinServer getConfiguration(String id, BuiltinServerConfiguration configuration);
+   BuiltinServer getConfiguration(String id, BuiltinServerConfiguration configuration);
 
-    //    BuiltinServer getConfiguration(String id, BuiltinServerConfiguration configuration, ConfigurationRequest request);
-    // void updateConfiguration(String id, xml?);
-    /*
+   //   BuiltinServer getConfiguration(String id, BuiltinServerConfiguration configuration, ConfigurationRequest request);
+   // void updateConfiguration(String id, xml?);
+   /*
 getDNSConfiguration(String id)
 getNATConfiguration(String id)
 getPolicyConfiguration(String id)
 getLBConfiguration(String id)
 
-     *    UpdateEFMConfiguration
-    BuiltinServer getConfiguration(String id, BuiltinServerConfiguration configuration);
+    *   UpdateEFMConfiguration
+   BuiltinServer getConfiguration(String id, BuiltinServerConfiguration configuration);
 
-     */
+    */
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerAsyncApi.java
index 569577f..b5b3bdc 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerAsyncApi.java
@@ -58,79 +58,79 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface BuiltinServerAsyncApi {
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "StartEFM")
-    ListenableFuture<Void> start(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "StartEFM")
+   ListenableFuture<Void> start(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "StopEFM")
-    ListenableFuture<Void> stop(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "StopEFM")
+   ListenableFuture<Void> stop(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DestroyEFM")
-    ListenableFuture<Void> destroy(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DestroyEFM")
+   ListenableFuture<Void> destroy(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "BackupEFM")
-    ListenableFuture<Void> backup(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "BackupEFM")
+   ListenableFuture<Void> backup(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "RestoreEFM")
-    ListenableFuture<Void> restore(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id,
-            @QueryParam("backupId") String backupId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "RestoreEFM")
+   ListenableFuture<Void> restore(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id,
+         @QueryParam("backupId") String backupId);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListEFMBackup")
-    ListenableFuture<Set<BuiltinServerBackup>> listBackups(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListEFMBackup")
+   ListenableFuture<Set<BuiltinServerBackup>> listBackups(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DestroyEFMBackup")
-    ListenableFuture<Void> destroyBackup(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id,
-            @QueryParam("backupId") String backupId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DestroyEFMBackup")
+   ListenableFuture<Void> destroyBackup(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id,
+         @QueryParam("backupId") String backupId);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetEFMAttributes")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<BuiltinServer> get(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetEFMAttributes")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<BuiltinServer> get(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UpdateEFMAttribute")
-    ListenableFuture<Void> update(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id,
-            @QueryParam("attributeName") String name,
-            @QueryParam("attributeValue") String value);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UpdateEFMAttribute")
+   ListenableFuture<Void> update(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id,
+         @QueryParam("attributeName") String name,
+         @QueryParam("attributeValue") String value);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetEFMStatus")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<BuiltinServerStatus> getStatus(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetEFMStatus")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<BuiltinServerStatus> getStatus(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetEFMConfiguration")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<BuiltinServer> getConfiguration(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id,
-            @QueryParam("configurationName") BuiltinServerConfiguration configuration);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetEFMConfiguration")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<BuiltinServer> getConfiguration(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("efmId") String id,
+         @QueryParam("configurationName") BuiltinServerConfiguration configuration);
 
 //  @POST
 //  @JAXBResponseParser
@@ -138,8 +138,8 @@
 //  @Transform(SingleElementResponseToElement.class)
 //  ListenableFuture<Set<Rule>> getUpdateDetails(String id);
 
-    // ListenableFuture<Void>
-    // updateConfiguration(@BinderParam(BindAlsoToSystemId.class)
-    // @QueryParam("efmId") String id, xml?);
-//    EFM_UPDATE,         getUpdateStatus(String id);
+   // ListenableFuture<Void>
+   // updateConfiguration(@BinderParam(BindAlsoToSystemId.class)
+   // @QueryParam("efmId") String id, xml?);
+//   EFM_UPDATE,       getUpdateStatus(String id);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/DiskImageApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/DiskImageApi.java
index 610e61d..294d282 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/DiskImageApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/DiskImageApi.java
@@ -31,9 +31,9 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface DiskImageApi {
 
-    DiskImage get(String id);
+   DiskImage get(String id);
 
-    void update(String diskImageId, String localeId, String name, String value);
+   void update(String diskImageId, String localeId, String name, String value);
 
-    void deregister(String id);
+   void deregister(String id);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/DiskImageAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/DiskImageAsyncApi.java
index 9b4d613..112a24d 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/DiskImageAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/DiskImageAsyncApi.java
@@ -51,23 +51,23 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface DiskImageAsyncApi {
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetDiskImageAttributes")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<DiskImage> get(@QueryParam("diskImageId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetDiskImageAttributes")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<DiskImage> get(@QueryParam("diskImageId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UpdateDiskImageAttribute")
-    ListenableFuture<Void> update(
-            @QueryParam("diskImageId") String diskImageId,
-            @QueryParam("updateLcId") String localeId,
-            @QueryParam("attributeName") String name,
-            @QueryParam("attributeValue") String value);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UpdateDiskImageAttribute")
+   ListenableFuture<Void> update(
+         @QueryParam("diskImageId") String diskImageId,
+         @QueryParam("updateLcId") String localeId,
+         @QueryParam("attributeName") String name,
+         @QueryParam("attributeValue") String value);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UnregisterDiskImage")
-    ListenableFuture<Void> deregister(@QueryParam("diskImageId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UnregisterDiskImage")
+   ListenableFuture<Void> deregister(@QueryParam("diskImageId") String id);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/FirewallApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/FirewallApi.java
index bfe54e9..bbb5067 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/FirewallApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/FirewallApi.java
@@ -32,6 +32,6 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface FirewallApi extends BuiltinServerApi {
 
-    Set<Rule> getNATConfiguration(String id);
-    
+   Set<Rule> getNATConfiguration(String id);
+   
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/FirewallAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/FirewallAsyncApi.java
index df06dc9..597e15d 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/FirewallAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/FirewallAsyncApi.java
@@ -22,23 +22,15 @@
 import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
 import javax.ws.rs.POST;
-import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
 import org.jclouds.concurrent.Timeout;
 import org.jclouds.fujitsu.fgcp.FGCPAsyncApi;
-import org.jclouds.fujitsu.fgcp.binders.BindAlsoToSystemId;
 import org.jclouds.fujitsu.fgcp.compute.functions.SingleElementResponseToElement;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServer;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServerBackup;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServerConfiguration;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServerStatus;
 import org.jclouds.fujitsu.fgcp.domain.Rule;
 import org.jclouds.fujitsu.fgcp.filters.RequestAuthenticator;
 import org.jclouds.fujitsu.fgcp.reference.RequestParameters;
-import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.JAXBResponseParser;
 import org.jclouds.rest.annotations.PayloadParams;
 import org.jclouds.rest.annotations.QueryParams;
@@ -60,20 +52,20 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface FirewallAsyncApi extends BuiltinServerAsyncApi {
 
-    @POST
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetEFMConfiguration")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<Set<Rule>> getNATConfiguration(String id);
+   @POST
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetEFMConfiguration")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<Set<Rule>> getNATConfiguration(String id);
 
-    /*
-    FW_NAT_RULE,        getNATConfiguration(String id)
+   /*
+   FW_NAT_RULE,      getNATConfiguration(String id)
 
-    FW_DNS,         getDNSConfiguration(String id)
-    FW_POLICY,          getPolicyConfiguration(String id)
+   FW_DNS,       getDNSConfiguration(String id)
+   FW_POLICY,        getPolicyConfiguration(String id)
 
-    FW_LOG,         getFirewallLogs(String id);
-    FW_LIMIT_POLICY,
+   FW_LOG,       getFirewallLogs(String id);
+   FW_LIMIT_POLICY,
 
-     */
+    */
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/LoadBalancerAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/LoadBalancerAsyncApi.java
index a7a6452..4987128 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/LoadBalancerAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/LoadBalancerAsyncApi.java
@@ -18,32 +18,18 @@
  */
 package org.jclouds.fujitsu.fgcp.services;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
 import org.jclouds.concurrent.Timeout;
 import org.jclouds.fujitsu.fgcp.FGCPAsyncApi;
-import org.jclouds.fujitsu.fgcp.binders.BindAlsoToSystemId;
-import org.jclouds.fujitsu.fgcp.compute.functions.SingleElementResponseToElement;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServer;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServerBackup;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServerConfiguration;
-import org.jclouds.fujitsu.fgcp.domain.BuiltinServerStatus;
 import org.jclouds.fujitsu.fgcp.filters.RequestAuthenticator;
 import org.jclouds.fujitsu.fgcp.reference.RequestParameters;
-import org.jclouds.rest.annotations.BinderParam;
-import org.jclouds.rest.annotations.JAXBResponseParser;
 import org.jclouds.rest.annotations.PayloadParams;
 import org.jclouds.rest.annotations.QueryParams;
 import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.Transform;
-
-import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * Non-blocking API relating to a built-in server, also called extended function
@@ -58,12 +44,12 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface LoadBalancerAsyncApi extends BuiltinServerAsyncApi {
 
-    /*
-    SLB_RULE,           getLBConfiguration(String id)
-    SLB_LOAD_STATISTICS,    getLoadBalancerStats(String id)
-    SLB_ERROR_STATISTICS,   getLoadBalancerErrorStats(String id)
-    SLB_CERTIFICATE_LIST,   getLoadBalancerCerts(String id)
-    SLB_CONNECTION,     getLoadBalancerConnection(String id)
+   /*
+   SLB_RULE,         getLBConfiguration(String id)
+   SLB_LOAD_STATISTICS,   getLoadBalancerStats(String id)
+   SLB_ERROR_STATISTICS,   getLoadBalancerErrorStats(String id)
+   SLB_CERTIFICATE_LIST,   getLoadBalancerCerts(String id)
+   SLB_CONNECTION,    getLoadBalancerConnection(String id)
 
-     */
+    */
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressApi.java
index 9bb4035..21771d7 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressApi.java
@@ -32,13 +32,13 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface PublicIPAddressApi {
 
-    void attach(String systemId, String ip);
+   void attach(String systemId, String ip);
 
-    void detach(String systemId, String ip);
+   void detach(String systemId, String ip);
 
-    void free(String systemId, String ip);
+   void free(String systemId, String ip);
 
-    PublicIPStatus getStatus(String ip);
+   PublicIPStatus getStatus(String ip);
 
-    PublicIP get(String ip);
+   PublicIP get(String ip);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressAsyncApi.java
index 0b50dc7..5b26fa1 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressAsyncApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.fujitsu.fgcp.services;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.Consumes;
@@ -53,35 +52,35 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface PublicIPAddressAsyncApi {
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "AttachPublicIP")
-    ListenableFuture<Void> attach(@QueryParam("vsysId") String systemId,
-            @QueryParam("publicIp") String ip);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "AttachPublicIP")
+   ListenableFuture<Void> attach(@QueryParam("vsysId") String systemId,
+         @QueryParam("publicIp") String ip);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DetachPublicIP")
-    ListenableFuture<Void> detach(@QueryParam("vsysId") String systemId,
-            @QueryParam("publicIp") String ip);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DetachPublicIP")
+   ListenableFuture<Void> detach(@QueryParam("vsysId") String systemId,
+         @QueryParam("publicIp") String ip);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetPublicIPStatus")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<PublicIPStatus> getStatus(
-            @QueryParam("publicIp") String ip);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetPublicIPStatus")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<PublicIPStatus> getStatus(
+         @QueryParam("publicIp") String ip);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetPublicIPAttributes")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<PublicIP> get(@QueryParam("publicIp") String ip);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetPublicIPAttributes")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<PublicIP> get(@QueryParam("publicIp") String ip);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "FreePublicIP")
-    ListenableFuture<Void> free(@QueryParam("vsysId") String systemId,
-            @QueryParam("publicIp") String ip);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "FreePublicIP")
+   ListenableFuture<Void> free(@QueryParam("vsysId") String systemId,
+         @QueryParam("publicIp") String ip);
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateApi.java
index e995a72..16bfde8 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateApi.java
@@ -32,12 +32,12 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface SystemTemplateApi {
 
-    VSystemDescriptor get(String id);
+   VSystemDescriptor get(String id);
 
-    void update(String id, String localeId, String name, String value);
+   void update(String id, String localeId, String name, String value);
 
-    void deregister(String id);
+   void deregister(String id);
 
-    void deregisterPrivateTemplate(String id);
+   void deregisterPrivateTemplate(String id);
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateAsyncApi.java
index 74a93b2..0deb371 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateAsyncApi.java
@@ -52,30 +52,30 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface SystemTemplateAsyncApi {
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVSYSDescriptorConfiguration")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VSystemDescriptor> get(
-            @QueryParam("vsysDescriptorId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVSYSDescriptorConfiguration")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VSystemDescriptor> get(
+         @QueryParam("vsysDescriptorId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UpdateVSYSDescriptorAttribute")
-    ListenableFuture<Void> update(@QueryParam("vsysDescriptorId") String id,
-            @QueryParam("updateLcId") String localeId,
-            @QueryParam("attributeName") String name,
-            @QueryParam("attributeValue") String value);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UpdateVSYSDescriptorAttribute")
+   ListenableFuture<Void> update(@QueryParam("vsysDescriptorId") String id,
+         @QueryParam("updateLcId") String localeId,
+         @QueryParam("attributeName") String name,
+         @QueryParam("attributeValue") String value);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UnregisterVSYSDescriptor")
-    ListenableFuture<Void> deregister(
-            @QueryParam("vsysDescriptorId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UnregisterVSYSDescriptor")
+   ListenableFuture<Void> deregister(
+         @QueryParam("vsysDescriptorId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UnregisterPrivateVSYSDescriptor")
-    ListenableFuture<Void> deregisterPrivateTemplate(
-            @QueryParam("vsysDescriptorId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UnregisterPrivateVSYSDescriptor")
+   ListenableFuture<Void> deregisterPrivateTemplate(
+         @QueryParam("vsysDescriptorId") String id);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApi.java
index bb3ec35..03ec435 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApi.java
@@ -18,58 +18,67 @@
  */
 package org.jclouds.fujitsu.fgcp.services;
 
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.fujitsu.fgcp.domain.*;
-
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.fujitsu.fgcp.domain.AddressRange;
+import org.jclouds.fujitsu.fgcp.domain.DiskImage;
+import org.jclouds.fujitsu.fgcp.domain.EventLog;
+import org.jclouds.fujitsu.fgcp.domain.Information;
+import org.jclouds.fujitsu.fgcp.domain.PublicIP;
+import org.jclouds.fujitsu.fgcp.domain.ServerType;
+import org.jclouds.fujitsu.fgcp.domain.UsageInfo;
+import org.jclouds.fujitsu.fgcp.domain.VSystem;
+import org.jclouds.fujitsu.fgcp.domain.VSystemDescriptor;
+import org.jclouds.javax.annotation.Nullable;
+
 /**
  * API relating to the virtual data center.
  * 
+ * @see VirtualDCAsyncApi
  * @author Dies Koper
  */
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface VirtualDCApi {
 
-    String createVirtualSystem(String descriptorId, String name);
+   String createVirtualSystem(String descriptorId, String name);
 
-    Set<VSystem> listVirtualSystems();
+   Set<VSystem> listVirtualSystems();
 
-    // according to the manual it takes a 'String diskImageId' but value seems
-    // to be ignored
-    Set<ServerType> listServerTypes();
+   // according to the manual it takes a 'String diskImageId' but value seems
+   // to be ignored
+   Set<ServerType> listServerTypes();
 
-    Set<DiskImage> listDiskImages();
+   Set<DiskImage> listDiskImages();
 
-    Set<DiskImage> listDiskImages(String serverCategory,
-            String vsysDescriptorId);
+   Set<DiskImage> listDiskImages(@Nullable String serverCategory, String vsysDescriptorId);
 
-    Map<PublicIP, String> listPublicIPs();
+   Map<PublicIP, String> listPublicIPs();
 
-    void addAddressRange(String pipFrom, String pipTo);
+   void addAddressRange(String pipFrom, String pipTo);
 
-    void createAddressPool(String pipFrom, String pipTo);
+   void createAddressPool(String pipFrom, String pipTo);
 
-    void deleteAddressRange(String pipFrom, String pipTo);
+   void deleteAddressRange(String pipFrom, String pipTo);
 
-    Set<AddressRange> getAddressRange();
+   Set<AddressRange> getAddressRange();
 
-    Set<VSystemDescriptor> listVSYSDescriptor();
+   Set<VSystemDescriptor> listVSYSDescriptor();
 
-    Set<VSystemDescriptor> listVSYSDescriptor(String keyword, int estimateFrom,
-            int estimateTo);
+   Set<VSystemDescriptor> listVSYSDescriptor(String keyword, int estimateFrom,
+         int estimateTo);
 
-    Set<EventLog> getEventLogs(boolean all);
+   Set<EventLog> getEventLogs(boolean all);
 
-    Set<EventLog> getEventLogs();
+   Set<EventLog> getEventLogs();
 
-    Set<Information> getInformation(boolean all);
+   Set<Information> getInformation(boolean all);
 
-    Set<Information> getInformation();
+   Set<Information> getInformation();
 
-    Set<UsageInfo> getSystemUsage();
+   Set<UsageInfo> getSystemUsage();
 
-    Set<UsageInfo> getSystemUsage(String systemIds);
+   Set<UsageInfo> getSystemUsage(String systemIds);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualDCAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualDCAsyncApi.java
index ec4bad9..7836893 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualDCAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualDCAsyncApi.java
@@ -41,6 +41,7 @@
 import org.jclouds.fujitsu.fgcp.domain.VSystemDescriptor;
 import org.jclouds.fujitsu.fgcp.filters.RequestAuthenticator;
 import org.jclouds.fujitsu.fgcp.reference.RequestParameters;
+import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.rest.annotations.JAXBResponseParser;
 import org.jclouds.rest.annotations.PayloadParams;
 import org.jclouds.rest.annotations.QueryParams;
@@ -61,129 +62,129 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface VirtualDCAsyncApi {
 
-    // @POST
-    @GET
-    @JAXBResponseParser
-    // @XMLResponseParser(VSYSCreateHandler.class)
-    @QueryParams(keys = "Action", values = "CreateVSYS")
-    @Transform(SingleElementResponseToElement.class)
-    // @PayloadParams(keys = "Action", values = "CreateVSYS")
-    // @Produces(MediaType.TEXT_XML)
-    // @MapBinder(BindParamsToXmlPayload.class)
-    // ListenableFuture<String>
-    // createVirtualSystem(@PayloadParam("vsysDescriptorId") String
-    // vsysDescriptorId, @PayloadParam("vsysName") String vsysName);
-    ListenableFuture<String> createVirtualSystem(
-            @QueryParam("vsysDescriptorId") String descriptorId,
-            @QueryParam("vsysName") String name);
+   // @POST
+   @GET
+   @JAXBResponseParser
+   // @XMLResponseParser(VSYSCreateHandler.class)
+   @QueryParams(keys = "Action", values = "CreateVSYS")
+   @Transform(SingleElementResponseToElement.class)
+   // @PayloadParams(keys = "Action", values = "CreateVSYS")
+   // @Produces(MediaType.TEXT_XML)
+   // @MapBinder(BindParamsToXmlPayload.class)
+   // ListenableFuture<String>
+   // createVirtualSystem(@PayloadParam("vsysDescriptorId") String
+   // vsysDescriptorId, @PayloadParam("vsysName") String vsysName);
+   ListenableFuture<String> createVirtualSystem(
+         @QueryParam("vsysDescriptorId") String descriptorId,
+         @QueryParam("vsysName") String name);
 
-    @GET
-    @JAXBResponseParser
-    // @XMLResponseParser(VSYSListHandler.class)
-    @QueryParams(keys = "Action", values = "ListVSYS")
-    ListenableFuture<Set<VSystem>> listVirtualSystems();
+   @GET
+   @JAXBResponseParser
+   // @XMLResponseParser(VSYSListHandler.class)
+   @QueryParams(keys = "Action", values = "ListVSYS")
+   ListenableFuture<Set<VSystem>> listVirtualSystems();
 
-    @GET
-    @JAXBResponseParser
-    // according to the manual it takes a 'String diskImageId' but value seems
-    // to be ignored
-    @QueryParams(keys = { "Action", "diskImageId" }, values = {
-            "ListServerType", "dummy" })
-    // @XmlJavaTypeAdapter(SetOfServerTypesXMLAdapter.class)
-    // @XmlElement(type = ServerType.class)
-    ListenableFuture<Set<ServerType>> listServerTypes();
+   @GET
+   @JAXBResponseParser
+   // according to the manual it takes a 'String diskImageId' but value seems
+   // to be ignored
+   @QueryParams(keys = { "Action", "diskImageId" }, values = {
+         "ListServerType", "dummy" })
+   // @XmlJavaTypeAdapter(SetOfServerTypesXMLAdapter.class)
+   // @XmlElement(type = ServerType.class)
+   ListenableFuture<Set<ServerType>> listServerTypes();
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListDiskImage")
-    ListenableFuture<Set<DiskImage>> listDiskImages();
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListDiskImage")
+   ListenableFuture<Set<DiskImage>> listDiskImages();
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListDiskImage")
-    ListenableFuture<Set<DiskImage>> listDiskImages(
-            @QueryParam("serverCategory") String serverCategory,
-            @QueryParam("vsysDescriptorId") String vsysDescriptorId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListDiskImage")
+   ListenableFuture<Set<DiskImage>> listDiskImages(
+         @Nullable @QueryParam("serverCategory") String serverCategory,
+         @QueryParam("vsysDescriptorId") String vsysDescriptorId);
 
-    /**
-     *
-     * @return
-     * @see VirtualSystemAsyncApi#listPublicIPs(String)
-     */
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListPublicIP")
-    ListenableFuture<Map<PublicIP, String>> listPublicIPs();
+   /**
+    *
+    * @return
+    * @see VirtualSystemAsyncApi#listPublicIPs(String)
+    */
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListPublicIP")
+   ListenableFuture<Map<PublicIP, String>> listPublicIPs();
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "AddAddressRange")
-    ListenableFuture<Void> addAddressRange(
-            @QueryParam("pipFrom") String pipFrom,
-            @QueryParam("pipTo") String pipTo);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "AddAddressRange")
+   ListenableFuture<Void> addAddressRange(
+         @QueryParam("pipFrom") String pipFrom,
+         @QueryParam("pipTo") String pipTo);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "CreateAddressPool")
-    ListenableFuture<Void> createAddressPool(
-            @QueryParam("pipFrom") String pipFrom,
-            @QueryParam("pipTo") String pipTo);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "CreateAddressPool")
+   ListenableFuture<Void> createAddressPool(
+         @QueryParam("pipFrom") String pipFrom,
+         @QueryParam("pipTo") String pipTo);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DeleteAddressRange")
-    ListenableFuture<Void> deleteAddressRange(
-            @QueryParam("pipFrom") String pipFrom,
-            @QueryParam("pipTo") String pipTo);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DeleteAddressRange")
+   ListenableFuture<Void> deleteAddressRange(
+         @QueryParam("pipFrom") String pipFrom,
+         @QueryParam("pipTo") String pipTo);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetAddressRange")
-    ListenableFuture<Set<AddressRange>> getAddressRange();
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetAddressRange")
+   ListenableFuture<Set<AddressRange>> getAddressRange();
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListVSYSDescriptor")
-    ListenableFuture<Set<VSystemDescriptor>> listVSYSDescriptor();
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListVSYSDescriptor")
+   ListenableFuture<Set<VSystemDescriptor>> listVSYSDescriptor();
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListVSYSDescriptor")
-    ListenableFuture<Set<VSystemDescriptor>> listVSYSDescriptor(
-            @QueryParam("keyword") String keyword,
-            @QueryParam("estimateFrom") int estimateFrom,
-            @QueryParam("estimateTo") int estimateTo);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListVSYSDescriptor")
+   ListenableFuture<Set<VSystemDescriptor>> listVSYSDescriptor(
+         @QueryParam("keyword") String keyword,
+         @QueryParam("estimateFrom") int estimateFrom,
+         @QueryParam("estimateTo") int estimateTo);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetEventLog")
-    ListenableFuture<Set<EventLog>> getEventLogs();
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetEventLog")
+   ListenableFuture<Set<EventLog>> getEventLogs();
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetEventLog")
-    ListenableFuture<Set<EventLog>> getEventLogs(@QueryParam("all") boolean all);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetEventLog")
+   ListenableFuture<Set<EventLog>> getEventLogs(@QueryParam("all") boolean all);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetInformation")
-    ListenableFuture<Set<Information>> getInformation();
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetInformation")
+   ListenableFuture<Set<Information>> getInformation();
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetInformation")
-    ListenableFuture<Set<Information>> getInformation(
-            @QueryParam("all") boolean all);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetInformation")
+   ListenableFuture<Set<Information>> getInformation(
+         @QueryParam("all") boolean all);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetSystemUsage")
-    ListenableFuture<Set<UsageInfo>> getSystemUsage();
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetSystemUsage")
+   ListenableFuture<Set<UsageInfo>> getSystemUsage();
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetSystemUsage")
-    ListenableFuture<Set<UsageInfo>> getSystemUsage(
-            @QueryParam("systemIds") String systemIds);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetSystemUsage")
+   ListenableFuture<Set<UsageInfo>> getSystemUsage(
+         @QueryParam("systemIds") String systemIds);
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualServerApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualServerApi.java
index 70be613..e1dabaf 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualServerApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualServerApi.java
@@ -35,27 +35,27 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface VirtualServerApi {
 
-    void start(String id);
+   void start(String id);
 
-    void stop(String id);
+   void stop(String id);
 
-    void stopForcefully(String id);
+   void stopForcefully(String id);
 
-    void destroy(String id);
+   void destroy(String id);
 
-    VServer get(String id);
+   VServer get(String id);
 
-    VServerWithDetails getDetails(String id);
+   VServerWithDetails getDetails(String id);
 
-    void update(String id, String name, String value);
+   void update(String id, String name, String value);
 
-    VServerStatus getStatus(String id);
+   VServerStatus getStatus(String id);
 
-    String getInitialPassword(String id);
+   String getInitialPassword(String id);
 
-    void attachDisk(String serverId, String diskId);
+   void attachDisk(String serverId, String diskId);
 
-    Set<PerformanceInfo> getPerformanceInformation(String id, String interval);
+   Set<PerformanceInfo> getPerformanceInformation(String id, String interval);
 
-    void registerAsPrivateDiskImage(String xml);
+   void registerAsPrivateDiskImage(String xml);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualServerAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualServerAsyncApi.java
index 5159c3b..15d85a2 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualServerAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualServerAsyncApi.java
@@ -58,91 +58,91 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface VirtualServerAsyncApi {
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "StartVServer")
-    ListenableFuture<Void> start(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "StartVServer")
+   ListenableFuture<Void> start(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "StopVServer")
-    ListenableFuture<Void> stop(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "StopVServer")
+   ListenableFuture<Void> stop(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = { "Action", "force" }, values = { "StopVServer", "true" })
-    ListenableFuture<Void> stopForcefully(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = { "Action", "force" }, values = { "StopVServer", "true" })
+   ListenableFuture<Void> stopForcefully(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DestroyVServer")
-    ListenableFuture<Void> destroy(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DestroyVServer")
+   ListenableFuture<Void> destroy(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVServerAttributes")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VServer> get(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVServerAttributes")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VServer> get(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVServerConfiguration")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VServerWithDetails> getDetails(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVServerConfiguration")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VServerWithDetails> getDetails(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UpdateVServerAttribute")
-    ListenableFuture<Void> update(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id,
-            @QueryParam("attributeName") String name,
-            @QueryParam("attributeValue") String value);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UpdateVServerAttribute")
+   ListenableFuture<Void> update(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id,
+         @QueryParam("attributeName") String name,
+         @QueryParam("attributeValue") String value);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVServerStatus")
-    // @Transform(StringToVServerStatus.class)
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VServerStatus> getStatus(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVServerStatus")
+   // @Transform(StringToVServerStatus.class)
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VServerStatus> getStatus(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVServerInitialPassword")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<String> getInitialPassword(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVServerInitialPassword")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<String> getInitialPassword(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "AttachVDisk")
-    ListenableFuture<Void> attachDisk(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String serverId,
-            @QueryParam("vdiskId") String diskId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "AttachVDisk")
+   ListenableFuture<Void> attachDisk(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("vserverId") String serverId,
+         @QueryParam("vdiskId") String diskId);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetPerformanceInformation")
-    ListenableFuture<Set<PerformanceInfo>> getPerformanceInformation(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("serverId") String id,
-            @QueryParam("interval") String interval);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetPerformanceInformation")
+   ListenableFuture<Set<PerformanceInfo>> getPerformanceInformation(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("serverId") String id,
+         @QueryParam("interval") String interval);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetPerformanceInformation")
-    ListenableFuture<Set<PerformanceInfo>> getPerformanceInformation(
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("serverId") String id,
-            @QueryParam("dataType") String dataType,
-            @QueryParam("interval") String interval);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetPerformanceInformation")
+   ListenableFuture<Set<PerformanceInfo>> getPerformanceInformation(
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("serverId") String id,
+         @QueryParam("dataType") String dataType,
+         @QueryParam("interval") String interval);
 
-    @POST
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "RegisterPrivateDiskImage")
-    ListenableFuture<Void> registerAsPrivateDiskImage(String xml);
+   @POST
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "RegisterPrivateDiskImage")
+   ListenableFuture<Void> registerAsPrivateDiskImage(String xml);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemApi.java
index 5ec7020..3bc12cd 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemApi.java
@@ -38,37 +38,37 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface VirtualSystemApi {
 
-    void destroy(String id);
+   void destroy(String id);
 
-    VSystemStatus getStatus(String id);
+   VSystemStatus getStatus(String id);
 
-    VSystem get(String id);
+   VSystem get(String id);
 
-    VSystemWithDetails getDetails(String id);
+   VSystemWithDetails getDetails(String id);
 
-    void update(String id, String name, String value);
+   void update(String id, String name, String value);
 
-    void updateConfiguration(String id, String name, String value);
+   void updateConfiguration(String id, String name, String value);
 
-    String createServer(String name, String type, String diskImageId,
-            String networkId);
+   String createServer(String name, String type, String diskImageId,
+         String networkId);
 
-    Set<VServer> listServers(String id);
+   Set<VServer> listServers(String id);
 
-    String createBuiltinServer(String name, String networkId);
+   String createBuiltinServer(String name, String networkId);
 
-    Set<BuiltinServer> listBuiltinServers(String id, String type);
+   Set<BuiltinServer> listBuiltinServers(String id, String type);
 
-    String createDisk(String id, String name, int size);
+   String createDisk(String id, String name, int size);
 
-    Set<VDisk> listDisks(String id);
+   Set<VDisk> listDisks(String id);
 
-    void allocatePublicIP(String id);
+   void allocatePublicIP(String id);
 
-    Set<PublicIP> listPublicIPs(String id);
+   Set<PublicIP> listPublicIPs(String id);
 
-    String standByConsole(String id, String networkId);
+   String standByConsole(String id, String networkId);
 
-    void registerAsPrivateVSYSDescriptor(String id,
-            String vsysDescriptorXMLFilePath);
+   void registerAsPrivateVSYSDescriptor(String id,
+         String vsysDescriptorXMLFilePath);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemAsyncApi.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemAsyncApi.java
index c9d4d20..12a0275 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemAsyncApi.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemAsyncApi.java
@@ -60,115 +60,115 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface VirtualSystemAsyncApi {
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "DestroyVSYS")
-    ListenableFuture<Void> destroy(@QueryParam("vsysId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "DestroyVSYS")
+   ListenableFuture<Void> destroy(@QueryParam("vsysId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVSYSStatus")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VSystemStatus> getStatus(@QueryParam("vsysId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVSYSStatus")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VSystemStatus> getStatus(@QueryParam("vsysId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVSYSAttributes")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VSystem> get(@QueryParam("vsysId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVSYSAttributes")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VSystem> get(@QueryParam("vsysId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "GetVSYSConfiguration")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<VSystemWithDetails> getDetails(
-            @QueryParam("vsysId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "GetVSYSConfiguration")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<VSystemWithDetails> getDetails(
+         @QueryParam("vsysId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UpdateVSYSAttribute")
-    ListenableFuture<Void> update(@QueryParam("vsysId") String id,
-            @QueryParam("attributeName") String name,
-            @QueryParam("attributeValue") String value);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UpdateVSYSAttribute")
+   ListenableFuture<Void> update(@QueryParam("vsysId") String id,
+         @QueryParam("attributeName") String name,
+         @QueryParam("attributeValue") String value);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "UpdateVSYSConfiguration")
-    ListenableFuture<Void> updateConfiguration(@QueryParam("vsysId") String id,
-            @QueryParam("configurationName") String name,
-            @QueryParam("configurationValue") String value);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "UpdateVSYSConfiguration")
+   ListenableFuture<Void> updateConfiguration(@QueryParam("vsysId") String id,
+         @QueryParam("configurationName") String name,
+         @QueryParam("configurationValue") String value);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "CreateVServer")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<String> createServer(
-            @QueryParam("vserverName") String name,
-            @QueryParam("vserverType") String type,
-            @QueryParam("diskImageId") String diskImageId,
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("networkId") String networkId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "CreateVServer")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<String> createServer(
+         @QueryParam("vserverName") String name,
+         @QueryParam("vserverType") String type,
+         @QueryParam("diskImageId") String diskImageId,
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("networkId") String networkId);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListVServer")
-    ListenableFuture<Set<VServer>> listServers(@QueryParam("vsysId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListVServer")
+   ListenableFuture<Set<VServer>> listServers(@QueryParam("vsysId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "CreateVDisk")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<String> createDisk(@QueryParam("vsysId") String id,
-            @QueryParam("vdiskName") String name, @QueryParam("size") int size);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "CreateVDisk")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<String> createDisk(@QueryParam("vsysId") String id,
+         @QueryParam("vdiskName") String name, @QueryParam("size") int size);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListVDisk")
-    ListenableFuture<Set<VDisk>> listDisks(@QueryParam("vsysId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListVDisk")
+   ListenableFuture<Set<VDisk>> listDisks(@QueryParam("vsysId") String id);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "AllocatePublicIP")
-    ListenableFuture<Void> allocatePublicIP(@QueryParam("vsysId") String id);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "AllocatePublicIP")
+   ListenableFuture<Void> allocatePublicIP(@QueryParam("vsysId") String id);
 
-    /**
-     *
-     * @return
-     * @see VirtualDCAsyncApi#listPublicIPs()
-     */
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListPublicIP")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<Set<PublicIP>> listPublicIPs(
-            @QueryParam("vsysId") String id);
+   /**
+    *
+    * @return
+    * @see VirtualDCAsyncApi#listPublicIPs()
+    */
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListPublicIP")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<Set<PublicIP>> listPublicIPs(
+         @QueryParam("vsysId") String id);
 
-    @GET
-    @JAXBResponseParser
-    // SLB is the only built-in server that can currently be created so
-    // hard-code it
-    @QueryParams(keys = { "Action", "efmType" }, values = { "CreateEFM", "SLB" })
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<String> createBuiltinServer(
-            @QueryParam("efmName") String name,
-            @BinderParam(BindAlsoToSystemId.class) @QueryParam("networkId") String networkId);
+   @GET
+   @JAXBResponseParser
+   // SLB is the only built-in server that can currently be created so
+   // hard-code it
+   @QueryParams(keys = { "Action", "efmType" }, values = { "CreateEFM", "SLB" })
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<String> createBuiltinServer(
+         @QueryParam("efmName") String name,
+         @BinderParam(BindAlsoToSystemId.class) @QueryParam("networkId") String networkId);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "ListEFM")
-    ListenableFuture<Set<BuiltinServer>> listBuiltinServers(
-            @QueryParam("vsysId") String id, @QueryParam("efmType") String type);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "ListEFM")
+   ListenableFuture<Set<BuiltinServer>> listBuiltinServers(
+         @QueryParam("vsysId") String id, @QueryParam("efmType") String type);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "StandByConsole")
-    @Transform(SingleElementResponseToElement.class)
-    ListenableFuture<String> standByConsole(@QueryParam("vsysId") String id,
-            @QueryParam("networkId") String networkId);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "StandByConsole")
+   @Transform(SingleElementResponseToElement.class)
+   ListenableFuture<String> standByConsole(@QueryParam("vsysId") String id,
+         @QueryParam("networkId") String networkId);
 
-    @GET
-    @JAXBResponseParser
-    @QueryParams(keys = "Action", values = "RegisterPrivateVSYSDescriptor")
-    ListenableFuture<Void> registerAsPrivateVSYSDescriptor(
-            @QueryParam("vsysId") String id,
-            @QueryParam("vsysDescriptorXMLFilePath") String vsysDescriptorXMLFilePath);
+   @GET
+   @JAXBResponseParser
+   @QueryParams(keys = "Action", values = "RegisterPrivateVSYSDescriptor")
+   ListenableFuture<Void> registerAsPrivateVSYSDescriptor(
+         @QueryParam("vsysId") String id,
+         @QueryParam("vsysDescriptorXMLFilePath") String vsysDescriptorXMLFilePath);
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/BindParamsToXmlPayload.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/BindParamsToXmlPayload.java
index 0783787..1532073 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/BindParamsToXmlPayload.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/BindParamsToXmlPayload.java
@@ -18,18 +18,20 @@
  */
 package org.jclouds.fujitsu.fgcp.xml;
 
-import com.google.common.base.Strings;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
 import org.jclouds.fujitsu.fgcp.reference.RequestParameters;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.rest.MapBinder;
 import org.jclouds.rest.binders.BindToStringPayload;
 
-import javax.ws.rs.core.MediaType;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Map;
-
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.base.Strings;
 
 /**
  * Not currently used but leaving for reference when implementing multipart POST
@@ -38,59 +40,60 @@
  * @author Dies Koper
  */
 public class BindParamsToXmlPayload extends BindToStringPayload implements
-        MapBinder {
+      MapBinder {
 
-    @Override
-    public <R extends HttpRequest> R bindToRequest(R request,
-            Map<String, Object> mapParams) {
-        String action = checkNotNull(
-                mapParams.remove(RequestParameters.ACTION),
-                RequestParameters.ACTION).toString();
-        String version = Strings.nullToEmpty((String) mapParams
-                .remove(RequestParameters.VERSION));
+   @SuppressWarnings("unchecked")
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request,
+         Map<String, Object> mapParams) {
+      String action = checkNotNull(
+            mapParams.remove(RequestParameters.ACTION),
+            RequestParameters.ACTION).toString();
+      String version = Strings.nullToEmpty((String) mapParams
+            .remove(RequestParameters.VERSION));
 
-        StringBuilder xml = new StringBuilder();
-        xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
-        xml.append("<OViSSRequest>\r\n");
-        xml.append("  <Action>" + action + "</Action>\r\n");
+      StringBuilder xml = new StringBuilder();
+      xml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
+      xml.append("<OViSSRequest>\r\n");
+      xml.append("  <Action>" + action + "</Action>\r\n");
 
-        for (Map.Entry<String, Object> entry : mapParams.entrySet()) {
-            String key = entry.getKey();
-            xml.append("  <" + key + ">" + checkNotNull(mapParams.get(key))
-                    + "</" + key + ">\r\n");
-        }
+      for (Map.Entry<String, Object> entry : mapParams.entrySet()) {
+         String key = entry.getKey();
+         xml.append("  <" + key + ">" + checkNotNull(mapParams.get(key))
+               + "</" + key + ">\r\n");
+      }
 
-        xml.append("  <Version>" + version + "</Version>\r\n");
-        xml.append("  <Locale></Locale>\r\n"); // value inserted in
-                                               // RequestAuthenticator#filter
-        xml.append("  <AccessKeyId></AccessKeyId>\r\n"); // value inserted in
-                                                         // RequestAuthenticator#filter
-        xml.append("  <Signature></Signature>\r\n"); // value inserted in
-                                                     // RequestAuthenticator#filter
-        xml.append("</OViSSRequest>");
+      xml.append("  <Version>" + version + "</Version>\r\n");
+      xml.append("  <Locale></Locale>\r\n"); // value inserted in
+                                    // RequestAuthenticator#filter
+      xml.append("  <AccessKeyId></AccessKeyId>\r\n"); // value inserted in
+                                           // RequestAuthenticator#filter
+      xml.append("  <Signature></Signature>\r\n"); // value inserted in
+                                        // RequestAuthenticator#filter
+      xml.append("</OViSSRequest>");
 
-        request = super.bindToRequest(request, xml);
-        request.getPayload().getContentMetadata()
-                .setContentType(MediaType.TEXT_XML);
+      request = super.bindToRequest(request, xml);
+      request.getPayload().getContentMetadata()
+            .setContentType(MediaType.TEXT_XML);
 
-        // remove version query param if set as it was moved to the xml body
-        URI uri = request.getEndpoint();
-        URI uriWithoutQueryParams;
-        try {
-            uriWithoutQueryParams = new URI(uri.getScheme(), uri.getUserInfo(),
-                    uri.getHost(), uri.getPort(), uri.getPath(), null,
-                    uri.getFragment());
-        } catch (URISyntaxException e) {
-            // should never happen as we're copying the components from a URI
-            uriWithoutQueryParams = uri;
-        }
+      // remove version query param if set as it was moved to the xml body
+      URI uri = request.getEndpoint();
+      URI uriWithoutQueryParams;
+      try {
+         uriWithoutQueryParams = new URI(uri.getScheme(), uri.getUserInfo(),
+               uri.getHost(), uri.getPort(), uri.getPath(), null,
+               uri.getFragment());
+      } catch (URISyntaxException e) {
+         // should never happen as we're copying the components from a URI
+         uriWithoutQueryParams = uri;
+      }
 
-        return (R) request.toBuilder().endpoint(uriWithoutQueryParams).build();
-    }
+      return (R) request.toBuilder().endpoint(uriWithoutQueryParams).build();
+   }
 
-    @Override
-    public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
-        throw new IllegalArgumentException(
-                "BindParamsToXmlPayload needs bind parameters");
-    }
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object toBind) {
+      throw new IllegalArgumentException(
+            "BindParamsToXmlPayload needs bind parameters");
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/FGCPJAXBParser.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/FGCPJAXBParser.java
index b5349ab..7e8dfff 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/FGCPJAXBParser.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/FGCPJAXBParser.java
@@ -40,49 +40,49 @@
  */
 @Singleton
 public class FGCPJAXBParser implements XMLParser {
-    JAXBContext context;
+   JAXBContext context;
 
-    public FGCPJAXBParser() throws JAXBException {
-        context = JAXBContext.newInstance(VServerWithDetails.class.getPackage()
-                .getName()
-                + ":"
-                + ListServerTypeResponse.class.getPackage().getName(),
-                VServerWithDetails.class.getClassLoader());
-    }
+   public FGCPJAXBParser() throws JAXBException {
+      context = JAXBContext.newInstance(VServerWithDetails.class.getPackage()
+            .getName()
+            + ":"
+            + ListServerTypeResponse.class.getPackage().getName(),
+            VServerWithDetails.class.getClassLoader());
+   }
 
-    @Override
-    public String toXML(final Object src) throws IOException {
-        return toXML(src, src.getClass());
-    }
+   @Override
+   public String toXML(final Object src) throws IOException {
+      return toXML(src, src.getClass());
+   }
 
-    @Override
-    public <T> String toXML(final Object src, final Class<T> type)
-            throws IOException {
-        throw new UnsupportedOperationException(
-                "only marshaling from XML is implemented");
-    }
+   @Override
+   public <T> String toXML(final Object src, final Class<T> type)
+         throws IOException {
+      throw new UnsupportedOperationException(
+            "only marshaling from XML is implemented");
+   }
 
-    @SuppressWarnings("unchecked")
-    @Override
-    public <T> T fromXML(final String xml, final Class<T> type)
-            throws IOException {
-        T response = null;
-        try {
-            StringReader reader = new StringReader(xml);
+   @SuppressWarnings("unchecked")
+   @Override
+   public <T> T fromXML(final String xml, final Class<T> type)
+         throws IOException {
+      T response = null;
+      try {
+         StringReader reader = new StringReader(xml);
 
-            Unmarshaller unmarshaller = context.createUnmarshaller();
+         Unmarshaller unmarshaller = context.createUnmarshaller();
 
-            response = (T) unmarshaller.unmarshal(reader);
-        } catch (Exception ex) {
-            throw new IOException("Could not unmarshal document", ex);
-        }
+         response = (T) unmarshaller.unmarshal(reader);
+      } catch (Exception ex) {
+         throw new IOException("Could not unmarshal document", ex);
+      }
 
-        if (((StatusQuerable) response).isError()) {
-            throw new HttpException(
-                    ((StatusQuerable) response).getResponseMessage());
-        }
+      if (((StatusQuerable) response).isError()) {
+         throw new HttpException(
+               ((StatusQuerable) response).getResponseMessage());
+      }
 
-        return response;
-    }
+      return response;
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateEFMResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateEFMResponse.java
index 237fde5..8c3fdb9 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateEFMResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateEFMResponse.java
@@ -28,17 +28,17 @@
  */
 @XmlRootElement(name = "CreateEFMResponse")
 public class CreateEFMResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private String efmId;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private String efmId;
 
-    @Override
-    public String toString() {
-        return getElement();
-    }
+   @Override
+   public String toString() {
+      return getElement();
+   }
 
-    @Override
-    public String getElement() {
-        return efmId;
-    }
+   @Override
+   public String getElement() {
+      return efmId;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVDiskResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVDiskResponse.java
index b31a637..6bf1a1f 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVDiskResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVDiskResponse.java
@@ -28,17 +28,17 @@
  */
 @XmlRootElement(name = "CreateVDiskResponse")
 public class CreateVDiskResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private String vdiskId;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private String vdiskId;
 
-    @Override
-    public String toString() {
-        return getElement();
-    }
+   @Override
+   public String toString() {
+      return getElement();
+   }
 
-    @Override
-    public String getElement() {
-        return vdiskId;
-    }
+   @Override
+   public String getElement() {
+      return vdiskId;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVSYSResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVSYSResponse.java
index a18a3fa..61dd417 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVSYSResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVSYSResponse.java
@@ -28,17 +28,17 @@
  */
 @XmlRootElement(name = "CreateVSYSResponse")
 public class CreateVSYSResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private String vsysId;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private String vsysId;
 
-    @Override
-    public String toString() {
-        return getElement();
-    }
+   @Override
+   public String toString() {
+      return getElement();
+   }
 
-    @Override
-    public String getElement() {
-        return vsysId;
-    }
+   @Override
+   public String getElement() {
+      return vsysId;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVServerResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVServerResponse.java
index 6170ee4..7d7ddcd 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVServerResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/CreateVServerResponse.java
@@ -28,17 +28,17 @@
  */
 @XmlRootElement(name = "CreateVServerResponse")
 public class CreateVServerResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private String vserverId;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private String vserverId;
 
-    @Override
-    public String toString() {
-        return getElement();
-    }
+   @Override
+   public String toString() {
+      return getElement();
+   }
 
-    @Override
-    public String getElement() {
-        return vserverId;
-    }
+   @Override
+   public String getElement() {
+      return vserverId;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetAddressRangeResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetAddressRangeResponse.java
index 9ea5571..799b3df 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetAddressRangeResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetAddressRangeResponse.java
@@ -37,14 +37,14 @@
  */
 @XmlRootElement(name = "GetAddressRangeResponse")
 public class GetAddressRangeResponse extends
-        SetWithStatusResponse<AddressRange> {
-    @XmlElementWrapper(name = "addressranges")
-    @XmlElement(name = "addressrange")
-    private Set<AddressRange> ranges = new LinkedHashSet<AddressRange>();
+      SetWithStatusResponse<AddressRange> {
+   @XmlElementWrapper(name = "addressranges")
+   @XmlElement(name = "addressrange")
+   private Set<AddressRange> ranges = new LinkedHashSet<AddressRange>();
 
-    @Override
-    protected Set<AddressRange> delegate() {
-        return ranges == null ? ImmutableSet.<AddressRange> of() : Collections
-                .unmodifiableSet(ranges);
-    }
+   @Override
+   protected Set<AddressRange> delegate() {
+      return ranges == null ? ImmutableSet.<AddressRange> of() : Collections
+            .unmodifiableSet(ranges);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetDiskImageAttributesResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetDiskImageAttributesResponse.java
index ccef26f..a6c59cf 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetDiskImageAttributesResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetDiskImageAttributesResponse.java
@@ -18,11 +18,11 @@
  */
 package org.jclouds.fujitsu.fgcp.xml.internal;
 
-import org.jclouds.fujitsu.fgcp.domain.DiskImage;
-
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.jclouds.fujitsu.fgcp.domain.DiskImage;
+
 /**
  * Wrapper for GetDiskImageAttributesResponse.
  * 
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetDiskImageAttributesResponse")
 public class GetDiskImageAttributesResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(name = "diskimage")
-    private DiskImage diskImage;
+      SingleElementResponse {
+   @XmlElement(name = "diskimage")
+   private DiskImage diskImage;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public DiskImage getElement() {
-        return diskImage;
-    }
+   @Override
+   public DiskImage getElement() {
+      return diskImage;
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEFMAttributesResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEFMAttributesResponse.java
index 9764a9e..939d63e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEFMAttributesResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEFMAttributesResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetEFMAttributesResponse")
 public class GetEFMAttributesResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private BuiltinServer efm;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private BuiltinServer efm;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return efm;
-    }
+   @Override
+   public Object getElement() {
+      return efm;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEFMStatusResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEFMStatusResponse.java
index 34fa4c6..a243c80 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEFMStatusResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEFMStatusResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetEFMStatusResponse")
 public class GetEFMStatusResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private BuiltinServerStatus efmStatus;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private BuiltinServerStatus efmStatus;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return efmStatus;
-    }
+   @Override
+   public Object getElement() {
+      return efmStatus;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEventLogResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEventLogResponse.java
index c9f35d2..988d79d 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEventLogResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetEventLogResponse.java
@@ -37,13 +37,13 @@
  */
 @XmlRootElement(name = "GetEventLogResponse")
 public class GetEventLogResponse extends SetWithStatusResponse<EventLog> {
-    @XmlElementWrapper(name = "eventlogs")
-    @XmlElement(name = "eventlog")
-    private Set<EventLog> logs = new LinkedHashSet<EventLog>();
+   @XmlElementWrapper(name = "eventlogs")
+   @XmlElement(name = "eventlog")
+   private Set<EventLog> logs = new LinkedHashSet<EventLog>();
 
-    @Override
-    protected Set<EventLog> delegate() {
-        return logs == null ? ImmutableSet.<EventLog> of() : Collections
-                .unmodifiableSet(logs);
-    }
+   @Override
+   protected Set<EventLog> delegate() {
+      return logs == null ? ImmutableSet.<EventLog> of() : Collections
+            .unmodifiableSet(logs);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPerformanceInformationResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPerformanceInformationResponse.java
index e8c9290..2c3b5f5 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPerformanceInformationResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPerformanceInformationResponse.java
@@ -37,14 +37,14 @@
  */
 @XmlRootElement(name = "GetPerformanceInformationResponse")
 public class GetPerformanceInformationResponse extends
-        SetWithStatusResponse<PerformanceInfo> {
-    @XmlElementWrapper(name = "performanceinfos")
-    @XmlElement(name = "performanceinfo")
-    private Set<PerformanceInfo> stats = new LinkedHashSet<PerformanceInfo>();
+      SetWithStatusResponse<PerformanceInfo> {
+   @XmlElementWrapper(name = "performanceinfos")
+   @XmlElement(name = "performanceinfo")
+   private Set<PerformanceInfo> stats = new LinkedHashSet<PerformanceInfo>();
 
-    @Override
-    protected Set<PerformanceInfo> delegate() {
-        return stats == null ? ImmutableSet.<PerformanceInfo> of()
-                : Collections.unmodifiableSet(stats);
-    }
+   @Override
+   protected Set<PerformanceInfo> delegate() {
+      return stats == null ? ImmutableSet.<PerformanceInfo> of()
+            : Collections.unmodifiableSet(stats);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPublicIPAttributesResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPublicIPAttributesResponse.java
index d0a0488..cb4f958 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPublicIPAttributesResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPublicIPAttributesResponse.java
@@ -26,7 +26,6 @@
 
 import org.jclouds.fujitsu.fgcp.domain.PublicIP;
 
-
 import com.google.common.collect.Iterables;
 
 /**
@@ -36,18 +35,18 @@
  */
 @XmlRootElement(name = "GetPublicIPAttributesResponse")
 public class GetPublicIPAttributesResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElementWrapper(name = "publicips")
-    @XmlElement(name = "publicip")
-    private Set<PublicIP> publicIPs;
+      SingleElementResponse {
+   @XmlElementWrapper(name = "publicips")
+   @XmlElement(name = "publicip")
+   private Set<PublicIP> publicIPs;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return Iterables.getOnlyElement(publicIPs);
-    }
+   @Override
+   public Object getElement() {
+      return Iterables.getOnlyElement(publicIPs);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPublicIPStatusResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPublicIPStatusResponse.java
index 29e5ce9..69b4fc2 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPublicIPStatusResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetPublicIPStatusResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetPublicIPStatusResponse")
 public class GetPublicIPStatusResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private PublicIPStatus publicipStatus;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private PublicIPStatus publicipStatus;
 
-    @Override
-    public String toString() {
-        return publicipStatus.toString();
-    }
+   @Override
+   public String toString() {
+      return publicipStatus.toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return publicipStatus;
-    }
+   @Override
+   public Object getElement() {
+      return publicipStatus;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVDiskAttributesResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVDiskAttributesResponse.java
index 0634f00..cc486d1 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVDiskAttributesResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVDiskAttributesResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetVDiskAttributesResponse")
 public class GetVDiskAttributesResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private VDisk vdisk;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private VDisk vdisk;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return vdisk;
-    }
+   @Override
+   public Object getElement() {
+      return vdisk;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSAttributesResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSAttributesResponse.java
index 0833a4d..bd2ff35 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSAttributesResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSAttributesResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetVSYSAttributesResponse")
 public class GetVSYSAttributesResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(name = "vsys")
-    private VSystem system;
+      SingleElementResponse {
+   @XmlElement(name = "vsys")
+   private VSystem system;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return system;
-    }
+   @Override
+   public Object getElement() {
+      return system;
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSConfigurationResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSConfigurationResponse.java
index c593a3b..977a177 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSConfigurationResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSConfigurationResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetVSYSConfigurationResponse")
 public class GetVSYSConfigurationResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(name = "vsys")
-    private VSystemWithDetails system;
+      SingleElementResponse {
+   @XmlElement(name = "vsys")
+   private VSystemWithDetails system;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return system;
-    }
+   @Override
+   public Object getElement() {
+      return system;
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSDescriptorConfigurationResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSDescriptorConfigurationResponse.java
index af21f20..75e7a5e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSDescriptorConfigurationResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSDescriptorConfigurationResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetVSYSDescriptorConfigurationResponse")
 public class GetVSYSDescriptorConfigurationResponse extends StatusResponse
-        implements SingleElementResponse {
-    @XmlElement
-    private VSystemDescriptor vsysdescriptor;
+      implements SingleElementResponse {
+   @XmlElement
+   private VSystemDescriptor vsysdescriptor;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return vsysdescriptor;
-    }
+   @Override
+   public Object getElement() {
+      return vsysdescriptor;
+   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSStatusResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSStatusResponse.java
index 08d1dc9..074ea0b 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSStatusResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVSYSStatusResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetVSYSStatusResponse")
 public class GetVSYSStatusResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private VSystemStatus vsysStatus;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private VSystemStatus vsysStatus;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return vsysStatus;
-    }
+   @Override
+   public Object getElement() {
+      return vsysStatus;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerAttributesResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerAttributesResponse.java
index 404ccec..5f9637c 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerAttributesResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerAttributesResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetVServerAttributesResponse")
 public class GetVServerAttributesResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private VServer vserver;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private VServer vserver;
 
-    @Override
-    public String toString() {
-        return vserver.toString();
-    }
+   @Override
+   public String toString() {
+      return vserver.toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return vserver;
-    }
+   @Override
+   public Object getElement() {
+      return vserver;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerConfigurationResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerConfigurationResponse.java
index f69daa5..cebe6ce 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerConfigurationResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerConfigurationResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetVServerConfigurationResponse")
 public class GetVServerConfigurationResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private VServerWithDetails vserver;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private VServerWithDetails vserver;
 
-    @Override
-    public String toString() {
-        return vserver.toString();
-    }
+   @Override
+   public String toString() {
+      return vserver.toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return vserver;
-    }
+   @Override
+   public Object getElement() {
+      return vserver;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerInitialPasswordResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerInitialPasswordResponse.java
index f5a1a16..39f6ee3 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerInitialPasswordResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerInitialPasswordResponse.java
@@ -28,12 +28,12 @@
  */
 @XmlRootElement(name = "GetVServerInitialPasswordResponse")
 public class GetVServerInitialPasswordResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private String initialPassword;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private String initialPassword;
 
-    @Override
-    public Object getElement() {
-        return initialPassword;
-    }
+   @Override
+   public Object getElement() {
+      return initialPassword;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerStatusResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerStatusResponse.java
index ea22965..657c5b6 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerStatusResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/GetVServerStatusResponse.java
@@ -30,17 +30,17 @@
  */
 @XmlRootElement(name = "GetVServerStatusResponse")
 public class GetVServerStatusResponse extends StatusResponse implements
-        SingleElementResponse {
-    @XmlElement(required = true)
-    private VServerStatus vserverStatus;
+      SingleElementResponse {
+   @XmlElement(required = true)
+   private VServerStatus vserverStatus;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    public Object getElement() {
-        return vserverStatus;
-    }
+   @Override
+   public Object getElement() {
+      return vserverStatus;
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListDiskImageResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListDiskImageResponse.java
index 5e19ad6..339b472 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListDiskImageResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListDiskImageResponse.java
@@ -37,13 +37,13 @@
  */
 @XmlRootElement(name = "ListDiskImageResponse")
 public class ListDiskImageResponse extends SetWithStatusResponse<DiskImage> {
-    @XmlElementWrapper(name = "diskimages")
-    @XmlElement(name = "diskimage")
-    private Set<DiskImage> diskImages = new LinkedHashSet<DiskImage>();
+   @XmlElementWrapper(name = "diskimages")
+   @XmlElement(name = "diskimage")
+   private Set<DiskImage> diskImages = new LinkedHashSet<DiskImage>();
 
-    @Override
-    protected Set<DiskImage> delegate() {
-        return diskImages == null ? ImmutableSet.<DiskImage> of() : Collections
-                .unmodifiableSet(diskImages);
-    }
+   @Override
+   protected Set<DiskImage> delegate() {
+      return diskImages == null ? ImmutableSet.<DiskImage> of() : Collections
+            .unmodifiableSet(diskImages);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListEFMBackupResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListEFMBackupResponse.java
index a902625..2acbfd4 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListEFMBackupResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListEFMBackupResponse.java
@@ -37,14 +37,14 @@
  */
 @XmlRootElement(name = "ListEFMBackupResponse")
 public class ListEFMBackupResponse extends
-        SetWithStatusResponse<BuiltinServerBackup> {
-    @XmlElementWrapper(name = "backups")
-    @XmlElement(name = "backup")
-    private Set<BuiltinServerBackup> backup = new LinkedHashSet<BuiltinServerBackup>();
+      SetWithStatusResponse<BuiltinServerBackup> {
+   @XmlElementWrapper(name = "backups")
+   @XmlElement(name = "backup")
+   private Set<BuiltinServerBackup> backup = new LinkedHashSet<BuiltinServerBackup>();
 
-    @Override
-    protected Set<BuiltinServerBackup> delegate() {
-        return backup == null ? ImmutableSet.<BuiltinServerBackup> of()
-                : Collections.unmodifiableSet(backup);
-    }
+   @Override
+   protected Set<BuiltinServerBackup> delegate() {
+      return backup == null ? ImmutableSet.<BuiltinServerBackup> of()
+            : Collections.unmodifiableSet(backup);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListEFMResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListEFMResponse.java
index 9ebbb1a..cffa13f 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListEFMResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListEFMResponse.java
@@ -37,13 +37,13 @@
  */
 @XmlRootElement(name = "ListEFMResponse")
 public class ListEFMResponse extends SetWithStatusResponse<BuiltinServer> {
-    @XmlElementWrapper(name = "efms")
-    @XmlElement(name = "efm")
-    private Set<BuiltinServer> efm = new LinkedHashSet<BuiltinServer>();
+   @XmlElementWrapper(name = "efms")
+   @XmlElement(name = "efm")
+   private Set<BuiltinServer> efm = new LinkedHashSet<BuiltinServer>();
 
-    @Override
-    protected Set<BuiltinServer> delegate() {
-        return efm == null ? ImmutableSet.<BuiltinServer> of() : Collections
-                .unmodifiableSet(efm);
-    }
+   @Override
+   protected Set<BuiltinServer> delegate() {
+      return efm == null ? ImmutableSet.<BuiltinServer> of() : Collections
+            .unmodifiableSet(efm);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListPublicIPResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListPublicIPResponse.java
index 2b6c1a1..6ddfa79 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListPublicIPResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListPublicIPResponse.java
@@ -39,32 +39,32 @@
  */
 @XmlRootElement(name = "ListPublicIPResponse")
 public class ListPublicIPResponse extends
-        MapWithStatusResponse<PublicIP, String> implements
-        SingleElementResponse {
-    @XmlElementWrapper(name = "publicips")
-    @XmlElement(name = "publicip")
-    private Set<PublicIPWithSystemId> ips;
+      MapWithStatusResponse<PublicIP, String> implements
+      SingleElementResponse {
+   @XmlElementWrapper(name = "publicips")
+   @XmlElement(name = "publicip")
+   private Set<PublicIPWithSystemId> ips;
 
-    @Override
-    public String toString() {
-        return getElement().toString();
-    }
+   @Override
+   public String toString() {
+      return getElement().toString();
+   }
 
-    @Override
-    protected Map<PublicIP, String> delegate() {
-        Builder<PublicIP, String> returnVal = ImmutableMap.builder();
-        if (ips != null) {
+   @Override
+   protected Map<PublicIP, String> delegate() {
+      Builder<PublicIP, String> returnVal = ImmutableMap.builder();
+      if (ips != null) {
 
-            for (PublicIPWithSystemId ip : ips) {
-                returnVal.put(ip, ip.getVsysId());
-            }
-        }
-        return returnVal.build();
-    }
+         for (PublicIPWithSystemId ip : ips) {
+            returnVal.put(ip, ip.getVsysId());
+         }
+      }
+      return returnVal.build();
+   }
 
-    @Override
-    public Set<? extends PublicIP> getElement() {
-        return ips == null ? ImmutableSet.<PublicIP> of() : Collections
-                .unmodifiableSet(ips);
-    }
+   @Override
+   public Set<? extends PublicIP> getElement() {
+      return ips == null ? ImmutableSet.<PublicIP> of() : Collections
+            .unmodifiableSet(ips);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListServerTypeResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListServerTypeResponse.java
index 6d1e49e..c10b0c8 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListServerTypeResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListServerTypeResponse.java
@@ -36,13 +36,13 @@
  */
 @XmlRootElement(name = "ListServerTypeResponse")
 public class ListServerTypeResponse extends SetWithStatusResponse<ServerType> {
-    @XmlElementWrapper(name = "servertypes")
-    @XmlElement(name = "servertype")
-    private Set<ServerType> serverTypes;
+   @XmlElementWrapper(name = "servertypes")
+   @XmlElement(name = "servertype")
+   private Set<ServerType> serverTypes;
 
-    @Override
-    protected Set<ServerType> delegate() {
-        return serverTypes == null ? ImmutableSet.<ServerType> of()
-                : Collections.unmodifiableSet(serverTypes);
-    }
+   @Override
+   protected Set<ServerType> delegate() {
+      return serverTypes == null ? ImmutableSet.<ServerType> of()
+            : Collections.unmodifiableSet(serverTypes);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVDiskResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVDiskResponse.java
index 0489a93..3be8d5d 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVDiskResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVDiskResponse.java
@@ -37,13 +37,13 @@
  */
 @XmlRootElement(name = "ListVDiskResponse")
 public class ListVDiskResponse extends SetWithStatusResponse<VDisk> {
-    @XmlElementWrapper(name = "vdisks")
-    @XmlElement(name = "vdisk")
-    private Set<VDisk> disks = new LinkedHashSet<VDisk>();
+   @XmlElementWrapper(name = "vdisks")
+   @XmlElement(name = "vdisk")
+   private Set<VDisk> disks = new LinkedHashSet<VDisk>();
 
-    @Override
-    protected Set<VDisk> delegate() {
-        return disks == null ? ImmutableSet.<VDisk> of() : Collections
-                .unmodifiableSet(disks);
-    }
+   @Override
+   protected Set<VDisk> delegate() {
+      return disks == null ? ImmutableSet.<VDisk> of() : Collections
+            .unmodifiableSet(disks);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVSYSResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVSYSResponse.java
index 90826f6..0cce1b2 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVSYSResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVSYSResponse.java
@@ -37,13 +37,13 @@
  */
 @XmlRootElement(name = "ListVSYSResponse")
 public class ListVSYSResponse extends SetWithStatusResponse<VSystem> {
-    @XmlElementWrapper(name = "vsyss")
-    @XmlElement(name = "vsys")
-    private Set<VSystem> systems = new LinkedHashSet<VSystem>();
+   @XmlElementWrapper(name = "vsyss")
+   @XmlElement(name = "vsys")
+   private Set<VSystem> systems = new LinkedHashSet<VSystem>();
 
-    @Override
-    protected Set<VSystem> delegate() {
-        return systems == null ? ImmutableSet.<VSystem> of() : Collections
-                .unmodifiableSet(systems);
-    }
+   @Override
+   protected Set<VSystem> delegate() {
+      return systems == null ? ImmutableSet.<VSystem> of() : Collections
+            .unmodifiableSet(systems);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVServerResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVServerResponse.java
index 802a779..2d8dc4e 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVServerResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/ListVServerResponse.java
@@ -37,13 +37,13 @@
  */
 @XmlRootElement(name = "ListVServerResponse")
 public class ListVServerResponse extends SetWithStatusResponse<VServer> {
-    @XmlElementWrapper(name = "vservers")
-    @XmlElement(name = "vserver")
-    private Set<VServer> servers = new LinkedHashSet<VServer>();
+   @XmlElementWrapper(name = "vservers")
+   @XmlElement(name = "vserver")
+   private Set<VServer> servers = new LinkedHashSet<VServer>();
 
-    @Override
-    protected Set<VServer> delegate() {
-        return servers == null ? ImmutableSet.<VServer> of() : Collections
-                .unmodifiableSet(servers);
-    }
+   @Override
+   protected Set<VServer> delegate() {
+      return servers == null ? ImmutableSet.<VServer> of() : Collections
+            .unmodifiableSet(servers);
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/MapWithStatusResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/MapWithStatusResponse.java
index ffc5430..e0f841a 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/MapWithStatusResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/MapWithStatusResponse.java
@@ -18,10 +18,10 @@
  */
 package org.jclouds.fujitsu.fgcp.xml.internal;
 
-import com.google.common.collect.ForwardingMap;
-
 import javax.xml.bind.annotation.XmlElement;
 
+import com.google.common.collect.ForwardingMap;
+
 /**
  * Special base class extending (forwardable) Map with fields for the elements
  * that FGCP XML responses specify.
@@ -32,27 +32,27 @@
  * @author Dies Koper
  */
 public abstract class MapWithStatusResponse<K, V> extends ForwardingMap<K, V>
-        implements StatusQuerable {
-    @XmlElement(required = true)
-    private String responseMessage;
-    @XmlElement(required = true)
-    private String responseStatus;
+      implements StatusQuerable {
+   @XmlElement(required = true)
+   private String responseMessage;
+   @XmlElement(required = true)
+   private String responseStatus;
 
-    public String getResponseMessage() {
-        return responseMessage;
-    }
+   public String getResponseMessage() {
+      return responseMessage;
+   }
 
-    public String getResponseStatus() {
-        return responseStatus;
-    }
+   public String getResponseStatus() {
+      return responseStatus;
+   }
 
-    public boolean isError() {
-        return !"SUCCESS".equals(responseStatus);
-    }
+   public boolean isError() {
+      return !"SUCCESS".equals(responseStatus);
+   }
 
-    @Override
-    public String toString() {
-        return "StatusResponse{" + "responseMessage='" + responseMessage + '\''
-                + ", responseStatus='" + responseStatus + '\'' + '}';
-    }
+   @Override
+   public String toString() {
+      return "StatusResponse{" + "responseMessage='" + responseMessage + '\''
+            + ", responseStatus='" + responseStatus + '\'' + '}';
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/PublicIPWithSystemId.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/PublicIPWithSystemId.java
index fd9f18c..6995541 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/PublicIPWithSystemId.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/PublicIPWithSystemId.java
@@ -29,15 +29,15 @@
  */
 @XmlRootElement(name = "publicip")
 public class PublicIPWithSystemId extends PublicIP {
-    private String vsysId;
+   private String vsysId;
 
-    public String getVsysId() {
-        return vsysId;
-    }
+   public String getVsysId() {
+      return vsysId;
+   }
 
-    @Override
-    public String toString() {
-        return "PublicIP{" + "address='" + address + '\'' + ", IP version='"
-                + version + '\'' + ", vsysId='" + vsysId + '\'' + '}';
-    }
+   @Override
+   public String toString() {
+      return "PublicIP{" + "address='" + address + '\'' + ", IP version='"
+            + version + '\'' + ", vsysId='" + vsysId + '\'' + '}';
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/SetWithStatusResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/SetWithStatusResponse.java
index bb7158f..6ee4e7c 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/SetWithStatusResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/SetWithStatusResponse.java
@@ -18,10 +18,10 @@
  */
 package org.jclouds.fujitsu.fgcp.xml.internal;
 
-import com.google.common.collect.ForwardingSet;
-
 import javax.xml.bind.annotation.XmlElement;
 
+import com.google.common.collect.ForwardingSet;
+
 /**
  * Special base class extending (forwardable) Set with fields for the elements
  * that FGCP XML responses specify.
@@ -32,27 +32,27 @@
  * @author Dies Koper
  */
 public abstract class SetWithStatusResponse<T> extends ForwardingSet<T>
-        implements StatusQuerable {
-    @XmlElement(required = true)
-    private String responseMessage;
-    @XmlElement(required = true)
-    private String responseStatus;
+      implements StatusQuerable {
+   @XmlElement(required = true)
+   private String responseMessage;
+   @XmlElement(required = true)
+   private String responseStatus;
 
-    public String getResponseMessage() {
-        return responseMessage;
-    }
+   public String getResponseMessage() {
+      return responseMessage;
+   }
 
-    public String getResponseStatus() {
-        return responseStatus;
-    }
+   public String getResponseStatus() {
+      return responseStatus;
+   }
 
-    public boolean isError() {
-        return !"SUCCESS".equals(responseStatus);
-    }
+   public boolean isError() {
+      return !"SUCCESS".equals(responseStatus);
+   }
 
-    @Override
-    public String toString() {
-        return delegate().toString();
-    }
+   @Override
+   public String toString() {
+      return delegate().toString();
+   }
 
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/SingleElementResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/SingleElementResponse.java
index 759586f..4ced6da 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/SingleElementResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/SingleElementResponse.java
@@ -25,5 +25,5 @@
  */
 public interface SingleElementResponse {
 
-    Object getElement();
+   Object getElement();
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/StatusQuerable.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/StatusQuerable.java
index 9046c68..5a83701 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/StatusQuerable.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/StatusQuerable.java
@@ -24,9 +24,9 @@
  * @author Dies Koper
  */
 public interface StatusQuerable {
-    public String getResponseMessage();
+   public String getResponseMessage();
 
-    public String getResponseStatus();
+   public String getResponseStatus();
 
-    public boolean isError();
+   public boolean isError();
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/StatusResponse.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/StatusResponse.java
index 7ea3361..d9d7f06 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/StatusResponse.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/StatusResponse.java
@@ -19,7 +19,6 @@
 package org.jclouds.fujitsu.fgcp.xml.internal;
 
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
 
 /**
  * Base class with fields for the elements that FGCP XML responses specify.
@@ -27,34 +26,34 @@
  * @author Dies Koper
  */
 public abstract class StatusResponse implements StatusQuerable {
-    @XmlElement(required = true)
-    private String responseMessage;
-    @XmlElement(required = true)
-    private String responseStatus;
+   @XmlElement(required = true)
+   private String responseMessage;
+   @XmlElement(required = true)
+   private String responseStatus;
 
-    public String getResponseMessage() {
-        return responseMessage;
-    }
+   public String getResponseMessage() {
+      return responseMessage;
+   }
 
-    public void setResponseMessage(String responseMessage) {
-        this.responseMessage = responseMessage;
-    }
+   public void setResponseMessage(String responseMessage) {
+      this.responseMessage = responseMessage;
+   }
 
-    public String getResponseStatus() {
-        return responseStatus;
-    }
+   public String getResponseStatus() {
+      return responseStatus;
+   }
 
-    public void setResponseStatus(String responseStatus) {
-        this.responseStatus = responseStatus;
-    }
+   public void setResponseStatus(String responseStatus) {
+      this.responseStatus = responseStatus;
+   }
 
-    public boolean isError() {
-        return !"SUCCESS".equals(responseStatus);
-    }
+   public boolean isError() {
+      return !"SUCCESS".equals(responseStatus);
+   }
 
-    @Override
-    public String toString() {
-        return "StatusResponse{" + "responseMessage='" + responseMessage + '\''
-                + ", responseStatus='" + responseStatus + '\'' + '}';
-    }
+   @Override
+   public String toString() {
+      return "StatusResponse{" + "responseMessage='" + responseMessage + '\''
+            + ", responseStatus='" + responseStatus + '\'' + '}';
+   }
 }
diff --git a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/package-info.java b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/package-info.java
index 12b705b..1347685 100644
--- a/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/package-info.java
+++ b/labs/fgcp/src/main/java/org/jclouds/fujitsu/fgcp/xml/internal/package-info.java
@@ -22,7 +22,7 @@
 @XmlAccessorType(XmlAccessType.FIELD)
 package org.jclouds.fujitsu.fgcp.xml.internal;
 
-import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlSchema;
 
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPBaseTemplateBuilderLiveTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPBaseTemplateBuilderLiveTest.java
index 54388cd..66da95e 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPBaseTemplateBuilderLiveTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPBaseTemplateBuilderLiveTest.java
@@ -16,69 +16,69 @@
 import com.google.common.base.Predicates;
 
 public abstract class FGCPBaseTemplateBuilderLiveTest extends
-        BaseTemplateBuilderLiveTest {
+      BaseTemplateBuilderLiveTest {
 
-    @Override
-    protected Properties setupProperties() {
-        Properties overrides = super.setupProperties();
+   @Override
+   protected Properties setupProperties() {
+      Properties overrides = super.setupProperties();
 
-        String proxy = System.getenv("http_proxy");
-        if (proxy != null) {
+      String proxy = System.getenv("http_proxy");
+      if (proxy != null) {
 
-            String[] parts = proxy.split("http://|:|@");
+         String[] parts = proxy.split("http://|:|@");
 
-            overrides.setProperty(Constants.PROPERTY_PROXY_HOST,
-                    parts[parts.length - 2]);
-            overrides.setProperty(Constants.PROPERTY_PROXY_PORT,
-                    parts[parts.length - 1]);
+         overrides.setProperty(Constants.PROPERTY_PROXY_HOST,
+               parts[parts.length - 2]);
+         overrides.setProperty(Constants.PROPERTY_PROXY_PORT,
+               parts[parts.length - 1]);
 
-            if (parts.length >= 4) {
-                overrides.setProperty(Constants.PROPERTY_PROXY_USER,
-                        parts[parts.length - 4]);
-                overrides.setProperty(Constants.PROPERTY_PROXY_PASSWORD,
-                        parts[parts.length - 3]);
+         if (parts.length >= 4) {
+            overrides.setProperty(Constants.PROPERTY_PROXY_USER,
+                  parts[parts.length - 4]);
+            overrides.setProperty(Constants.PROPERTY_PROXY_PASSWORD,
+                  parts[parts.length - 3]);
+         }
+      }
+
+      // enables peer verification using the CAs bundled with the JRE (or
+      // value of javax.net.ssl.trustStore if set)
+      overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
+
+      return overrides;
+   }
+
+   @Override
+   protected Predicate<OsFamilyVersion64Bit> defineUnsupportedOperatingSystems() {
+      return Predicates.not(new Predicate<OsFamilyVersion64Bit>() {
+
+         @Override
+         public boolean apply(OsFamilyVersion64Bit input) {
+            switch (input.family) {
+            case CENTOS:
+               return input.version.matches("5.[46]")
+                     || input.version.equals("6.[2]");
+            case WINDOWS:
+               return (input.version.equals("2008 R2 SE") || input.version
+                     .equals("2008 R2 EE")) && input.is64Bit;
+            default:
+               return false;
             }
-        }
+         }
 
-        // enables peer verification using the CAs bundled with the JRE (or
-        // value of javax.net.ssl.trustStore if set)
-        overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
+      });
+   }
 
-        return overrides;
-    }
-
-    @Override
-    protected Predicate<OsFamilyVersion64Bit> defineUnsupportedOperatingSystems() {
-        return Predicates.not(new Predicate<OsFamilyVersion64Bit>() {
-
-            @Override
-            public boolean apply(OsFamilyVersion64Bit input) {
-                switch (input.family) {
-                case CENTOS:
-                    return input.version.matches("5.[46]")
-                            || input.version.equals("6.[2]");
-                case WINDOWS:
-                    return (input.version.equals("2008 R2 SE") || input.version
-                            .equals("2008 R2 EE")) && input.is64Bit;
-                default:
-                    return false;
-                }
-            }
-
-        });
-    }
-
-    public void testDefaultTemplateBuilder() throws IOException {
-        Template defaultTemplate = view.getComputeService().templateBuilder()
-                .build();
-        assert defaultTemplate.getImage().getOperatingSystem().getVersion()
-                .matches("6.2") : defaultTemplate.getImage()
-                .getOperatingSystem().getVersion();
-        assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(),
-                true);
-        assertEquals(defaultTemplate.getImage().getOperatingSystem()
-                .getFamily(), OsFamily.CENTOS);
-        assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
-    }
+   public void testDefaultTemplateBuilder() throws IOException {
+      Template defaultTemplate = view.getComputeService().templateBuilder()
+            .build();
+      assert defaultTemplate.getImage().getOperatingSystem().getVersion()
+            .matches("6.2") : defaultTemplate.getImage()
+            .getOperatingSystem().getVersion();
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(),
+            true);
+      assertEquals(defaultTemplate.getImage().getOperatingSystem()
+            .getFamily(), OsFamily.CENTOS);
+      assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
+   }
 
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPRestClientModuleTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPRestClientModuleTest.java
index 9c1c880..2706e97 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPRestClientModuleTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/FGCPRestClientModuleTest.java
@@ -18,15 +18,8 @@
  */
 package org.jclouds.fujitsu.fgcp.compute;
 
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import org.jclouds.crypto.Crypto;
-import org.jclouds.fujitsu.fgcp.FGCPApiMetadata;
+import static org.testng.Assert.assertNotNull;
 
-import org.testng.annotations.BeforeTest;
-import org.testng.annotations.Test;
-
-import java.io.File;
 import java.io.IOException;
 import java.net.URL;
 import java.security.KeyStore;
@@ -34,9 +27,13 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
 import java.security.spec.InvalidKeySpecException;
-import java.util.Scanner;
 
-import static org.testng.Assert.*;
+import org.jclouds.crypto.Crypto;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
 
 /**
  * @author Dies Koper
@@ -44,55 +41,55 @@
 @Test(groups = "unit", testName = "FGCPRestClientModuleTest")
 public class FGCPRestClientModuleTest {
 
-    protected FGCPRestClientModule module;
-    protected Crypto crypto;
+   protected FGCPRestClientModule module;
+   protected Crypto crypto;
 
-    @BeforeTest
-    protected void createCrypto() {
-        Injector i = Guice.createInjector();
-        crypto = i.getInstance(Crypto.class);
-    }
+   @BeforeTest
+   protected void createCrypto() {
+      Injector i = Guice.createInjector();
+      crypto = i.getInstance(Crypto.class);
+   }
 
-    @BeforeTest
-    protected void createRestClientModule() {
-        Injector i = Guice.createInjector();
-        module = i.getInstance(FGCPRestClientModule.class);
-    }
+   @BeforeTest
+   protected void createRestClientModule() {
+      Injector i = Guice.createInjector();
+      module = i.getInstance(FGCPRestClientModule.class);
+   }
 
-    public void testKeyStoreAsPkcs12() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, KeyStoreException, CertificateException {
-        assertNotNull(crypto);
-        assertNotNull(module);
+   public void testKeyStoreAsPkcs12() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, KeyStoreException, CertificateException {
+      assertNotNull(crypto);
+      assertNotNull(module);
 
-        // self-signed dummy cert:
-        // keytool -genkey -alias test-fgcp -keyalg RSA -keysize 1024 -validity 5475 -dname "CN=localhost" -keystore jclouds-test-fgcp.p12 -storepass jcloudsjclouds -storetype pkcs12
-        String cert = "/certs/jclouds-test-fgcp.p12";
-        String keyPassword = "jcloudsjclouds";
+      // self-signed dummy cert:
+      // keytool -genkey -alias test-fgcp -keyalg RSA -keysize 1024 -validity 5475 -dname "CN=localhost" -keystore jclouds-test-fgcp.p12 -storepass jcloudsjclouds -storetype pkcs12
+      String cert = "/certs/jclouds-test-fgcp.p12";
+      String keyPassword = "jcloudsjclouds";
 
-        URL url = this.getClass().getResource(cert);
-        String certPath = url.getFile();
+      URL url = this.getClass().getResource(cert);
+      String certPath = url.getFile();
 
-        KeyStore ks = module.provideKeyStore(crypto, certPath, keyPassword);
+      KeyStore ks = module.provideKeyStore(crypto, certPath, keyPassword);
 
-        assertNotNull(ks.getCertificate("test-fgcp"), "cert with alias");
-    }
+      assertNotNull(ks.getCertificate("test-fgcp"), "cert with alias");
+   }
 
-/*    public void testKeyStoreAsPEM() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, KeyStoreException, CertificateException {
-        assertNotNull(crypto);
-        assertNotNull(module);
+/*   public void testKeyStoreAsPEM() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, KeyStoreException, CertificateException {
+      assertNotNull(crypto);
+      assertNotNull(module);
 
-        //openssl pkcs12 -nodes -in jclouds-test-fgcp.p12 -out jclouds-test-fgcp.pem
-//        String privKeyFilename = "D:\\UserCert.pem.pkcs12-nodes";//_nobags";
-        String cert = "/certs/jclouds-test-fgcp.pem";
-        String keyPassword = "jcloudsjclouds";
+      //openssl pkcs12 -nodes -in jclouds-test-fgcp.p12 -out jclouds-test-fgcp.pem
+//      String privKeyFilename = "D:\\UserCert.pem.pkcs12-nodes";//_nobags";
+      String cert = "/certs/jclouds-test-fgcp.pem";
+      String keyPassword = "jcloudsjclouds";
 
-        URL url = this.getClass().getResource(cert);
-        String certPath = url.getFile();
-        Scanner scanner = new Scanner(new File(certPath));
-        String content = scanner.useDelimiter("\\A").next();
+      URL url = this.getClass().getResource(cert);
+      String certPath = url.getFile();
+      Scanner scanner = new Scanner(new File(certPath));
+      String content = scanner.useDelimiter("\\A").next();
 
-        KeyStore ks = module.provideKeyStore(crypto, content, keyPassword);
+      KeyStore ks = module.provideKeyStore(crypto, content, keyPassword);
 
-        assertNotNull(ks.getCertificate("test-fgcp"), "cert with alias");
-    }
+      assertNotNull(ks.getCertificate("test-fgcp"), "cert with alias");
+   }
 */
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPBaseComputeServiceLiveTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPBaseComputeServiceLiveTest.java
index 996965b..c51c2dc 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPBaseComputeServiceLiveTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/config/FGCPBaseComputeServiceLiveTest.java
@@ -15,173 +15,173 @@
 import com.google.inject.Module;
 
 public abstract class FGCPBaseComputeServiceLiveTest extends
-        BaseComputeServiceLiveTest {
+      BaseComputeServiceLiveTest {
 
-    @Override
-    protected Properties setupProperties() {
-        Properties overrides = super.setupProperties();
-    
-        String proxy = System.getenv("http_proxy");
-        if (proxy != null) {
-    
-            String[] parts = proxy.split("http://|:|@");
-    
-            overrides.setProperty(Constants.PROPERTY_PROXY_HOST, parts[parts.length - 2]);
-            overrides.setProperty(Constants.PROPERTY_PROXY_PORT, parts[parts.length - 1]);
-    
-            if (parts.length >= 4) {
-                overrides.setProperty(Constants.PROPERTY_PROXY_USER, parts[parts.length - 4]);
-                overrides.setProperty(Constants.PROPERTY_PROXY_PASSWORD, parts[parts.length - 3]);
-            }
-        }
-    
-        // enables peer verification using the CAs bundled with the JRE (or
-        // value of javax.net.ssl.trustStore if set)
-        overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
-    
-        return overrides;
+   @Override
+   protected Properties setupProperties() {
+      Properties overrides = super.setupProperties();
+   
+      String proxy = System.getenv("http_proxy");
+      if (proxy != null) {
+   
+         String[] parts = proxy.split("http://|:|@");
+   
+         overrides.setProperty(Constants.PROPERTY_PROXY_HOST, parts[parts.length - 2]);
+         overrides.setProperty(Constants.PROPERTY_PROXY_PORT, parts[parts.length - 1]);
+   
+         if (parts.length >= 4) {
+            overrides.setProperty(Constants.PROPERTY_PROXY_USER, parts[parts.length - 4]);
+            overrides.setProperty(Constants.PROPERTY_PROXY_PASSWORD, parts[parts.length - 3]);
+         }
+      }
+   
+      // enables peer verification using the CAs bundled with the JRE (or
+      // value of javax.net.ssl.trustStore if set)
+      overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
+   
+      return overrides;
+   }
+
+   @Override
+   protected Module getSshModule() {
+      return new SshjSshClientModule();
+   }
+
+   @Override
+   @Test(enabled = false, expectedExceptions = AuthorizationException.class)
+   public void testCorrectAuthException() throws Exception {
+      // http://code.google.com/p/jclouds/issues/detail?id=1060
+   }
+
+   // fgcp does not support metadata
+   @Override
+   protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
+      assert node.getUserMetadata().isEmpty() : String.format(
+            "node userMetadata not empty: %s %s", node,
+            node.getUserMetadata());
     }
 
-    @Override
-    protected Module getSshModule() {
-       return new SshjSshClientModule();
-    }
+   // node name can't be retrieved through the API and is therefore null
+   protected void checkResponseEqualsHostname(ExecResponse execResponse,
+         NodeMetadata node) {
+      assert node.getHostname() == null : node + " with hostname: "
+            + node.getHostname();
+   }
 
-    @Override
-    @Test(enabled = false, expectedExceptions = AuthorizationException.class)
-    public void testCorrectAuthException() throws Exception {
-        // http://code.google.com/p/jclouds/issues/detail?id=1060
-    }
+   // tags are not (yet) supported for fgcp
+   protected void checkTagsInNodeEquals(NodeMetadata node,
+         ImmutableSet<String> tags) {
+      assert node.getTags().isEmpty() : String.format(
+            "node tags found %s (%s) in node %s", node.getTags(), tags, node);
+   }
 
-    // fgcp does not support metadata
-    @Override
-    protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap<String, String> userMetadata) {
-        assert node.getUserMetadata().isEmpty() : String.format(
-                "node userMetadata not empty: %s %s", node,
-                node.getUserMetadata());
-     }
+   /*
+    * public void testCreateAndRunAService() throws Exception {
+    * super.testCreateAndRunAService(); }
+    */
 
-    // node name can't be retrieved through the API and is therefore null
-    protected void checkResponseEqualsHostname(ExecResponse execResponse,
-            NodeMetadata node) {
-        assert node.getHostname() == null : node + " with hostname: "
-                + node.getHostname();
-    }
+   // this test requires network access to the VM it creates:
+   // before running it, start an SSL/VPN connection to the last updated vsys'
+   // DMZ.
+   // may also need to configure SNAT and FW rules to allow the VM to
+   // communicate out (53 for DNS, 80 for yum).
+   public void testAScriptExecutionAfterBootWithBasicTemplate()
+         throws Exception {
+      super.testAScriptExecutionAfterBootWithBasicTemplate();
+   }
 
-    // tags are not (yet) supported for fgcp
-    protected void checkTagsInNodeEquals(NodeMetadata node,
-            ImmutableSet<String> tags) {
-        assert node.getTags().isEmpty() : String.format(
-                "node tags found %s (%s) in node %s", node.getTags(), tags, node);
-    }
+   @Override
+   @Test(enabled = false)
+   public void testOptionToNotBlock() throws Exception {
+      // start call returns before node reaches running state, but
+      // test may be failing due to the system being in a 're-configuring'
+      // state while destroying nodes of a previous test.
+      // http://code.google.com/p/jclouds/issues/detail?id=1066
+         /*
+   org.jclouds.compute.RunNodesException: error running 1 node group(fgcp-aublock) location(UZXC0GRT-IZKDVGIL5-N-SECURE1) image(IMG_3c9820_71OW9NZC268) size(islanda-cbrm_140) options({inboundPorts=[], blockUntilRunning=false})
+   Execution failures:
+   
+   1) ExecutionException on fgcp-aublock-787:
+   java.util.concurrent.ExecutionException: java.lang.IllegalStateException: The status of Instance[UZXC0GRT-IZKDVGIL5] is [RECONFIG_ING].
+      at com.google.common.util.concurrent.AbstractFuture$Sync.getValue(AbstractFuture.java:289)
+      at com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:276)
+      at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:111)
+      at org.jclouds.concurrent.FutureIterables$1.run(FutureIterables.java:134)
+      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
+      at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+      at java.lang.Thread.run(Unknown Source)
+   Caused by: java.lang.IllegalStateException: The status of Instance[UZXC0GRT-IZKDVGIL5] is [RECONFIG_ING].
+      at org.jclouds.fujitsu.fgcp.xml.FGCPJAXBParser.fromXML(FGCPJAXBParser.java:75)
+      at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:91)
+      at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:86)
+      at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:73)
+      at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:54)
+      at com.google.common.base.Functions$FunctionComposition.apply(Functions.java:209)
+      at com.google.common.util.concurrent.Futures$3.apply(Futures.java:380)
+      at com.google.common.util.concurrent.Futures$ChainingListenableFuture.run(Futures.java:522)
+      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
+      at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+      at java.lang.Thread.run(Unknown Source)
+      at org.jclouds.concurrent.config.DescribingExecutorService.submit(DescribingExecutorService.java:89)
+      at org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.createNodeInGroupWithNameAndTemplate(CreateNodesWithGroupEncodedIntoNameThenAddToSet.java:170)
+      at org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.execute(CreateNodesWithGroupEncodedIntoNameThenAddToSet.java:125)
+      at org.jclouds.compute.internal.BaseComputeService.createNodesInGroup(BaseComputeService.java:213)
+      at org.jclouds.compute.internal.BaseComputeService.createNodesInGroup(BaseComputeService.java:229)
+      at org.jclouds.compute.internal.BaseComputeServiceLiveTest.testOptionToNotBlock(BaseComputeServiceLiveTest.java:803)
+          */
+      }
 
-    /*
-     * public void testCreateAndRunAService() throws Exception {
-     * super.testCreateAndRunAService(); }
-     */
+/*   @Override
+   @Test(enabled = false)
+   public void testCreateTwoNodesWithRunScript() {
+   }
 
-    // this test requires network access to the VM it creates:
-    // before running it, start an SSL/VPN connection to the last updated vsys'
-    // DMZ.
-    // may also need to configure SNAT and FW rules to allow the VM to
-    // communicate out (53 for DNS, 80 for yum).
-    public void testAScriptExecutionAfterBootWithBasicTemplate()
-            throws Exception {
-        super.testAScriptExecutionAfterBootWithBasicTemplate();
-    }
+   @Override
+   @Test(enabled = false)
+   public void testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired() {
+   }
 
-    @Override
-    @Test(enabled = false)
-    public void testOptionToNotBlock() throws Exception {
-        // start call returns before node reaches running state, but
-        // test may be failing due to the system being in a 're-configuring'
-        // state while destroying nodes of a previous test.
-        // http://code.google.com/p/jclouds/issues/detail?id=1066
-            /*
-    org.jclouds.compute.RunNodesException: error running 1 node group(fgcp-aublock) location(UZXC0GRT-IZKDVGIL5-N-SECURE1) image(IMG_3c9820_71OW9NZC268) size(islanda-cbrm_140) options({inboundPorts=[], blockUntilRunning=false})
-    Execution failures:
-    
-    1) ExecutionException on fgcp-aublock-787:
-    java.util.concurrent.ExecutionException: java.lang.IllegalStateException: The status of Instance[UZXC0GRT-IZKDVGIL5] is [RECONFIG_ING].
-        at com.google.common.util.concurrent.AbstractFuture$Sync.getValue(AbstractFuture.java:289)
-        at com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:276)
-        at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:111)
-        at org.jclouds.concurrent.FutureIterables$1.run(FutureIterables.java:134)
-        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
-        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
-        at java.lang.Thread.run(Unknown Source)
-    Caused by: java.lang.IllegalStateException: The status of Instance[UZXC0GRT-IZKDVGIL5] is [RECONFIG_ING].
-        at org.jclouds.fujitsu.fgcp.xml.FGCPJAXBParser.fromXML(FGCPJAXBParser.java:75)
-        at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:91)
-        at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:86)
-        at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:73)
-        at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:54)
-        at com.google.common.base.Functions$FunctionComposition.apply(Functions.java:209)
-        at com.google.common.util.concurrent.Futures$3.apply(Futures.java:380)
-        at com.google.common.util.concurrent.Futures$ChainingListenableFuture.run(Futures.java:522)
-        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
-        at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
-        at java.lang.Thread.run(Unknown Source)
-        at org.jclouds.concurrent.config.DescribingExecutorService.submit(DescribingExecutorService.java:89)
-        at org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.createNodeInGroupWithNameAndTemplate(CreateNodesWithGroupEncodedIntoNameThenAddToSet.java:170)
-        at org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.execute(CreateNodesWithGroupEncodedIntoNameThenAddToSet.java:125)
-        at org.jclouds.compute.internal.BaseComputeService.createNodesInGroup(BaseComputeService.java:213)
-        at org.jclouds.compute.internal.BaseComputeService.createNodesInGroup(BaseComputeService.java:229)
-        at org.jclouds.compute.internal.BaseComputeServiceLiveTest.testOptionToNotBlock(BaseComputeServiceLiveTest.java:803)
-             */
-        }
-
-/*    @Override
-    @Test(enabled = false)
-    public void testCreateTwoNodesWithRunScript() {
-    }
-
-    @Override
-    @Test(enabled = false)
-    public void testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired() {
-    }
-
-    @Override
-    @Test(enabled = false)
-    public void testGet() {
-    }
+   @Override
+   @Test(enabled = false)
+   public void testGet() {
+   }
 */
-//    @Override
-//    @Test(enabled = false)
-//    public void testConcurrentUseOfComputeServiceToCreateNodes() throws Exception {
-        // http://code.google.com/p/jclouds/issues/detail?id=1066
-        /*
-        1) ExecutionException on twin0-f6a:
-            java.util.concurrent.ExecutionException: org.jclouds.http.HttpResponseException: Error parsing input
-            {statusCode=200, message=OK, headers={Date=[Sun, 26 Aug 2012 01:22:50 GMT], Transfer-Encoding=[chunked], Set-Cookie=[JSESSIONID=8A07404DF0405E46B3A748C3763B0D9F; Path=/ovisspxy; Secure], Connection=[close]}, payload=[content=true, contentMetadata=[contentDisposition=null, contentEncoding=null, contentLanguage=null, contentLength=null, contentMD5=null, contentType=text/xml;charset=UTF-8, expires=null], written=false]}
-                at com.google.common.util.concurrent.AbstractFuture$Sync.getValue(AbstractFuture.java:289)
-                at com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:276)
-                at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:111)
-                at org.jclouds.concurrent.FutureIterables$1.run(FutureIterables.java:134)
-                at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
-                at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
-                at java.lang.Thread.run(Unknown Source)
-            Caused by: org.jclouds.http.HttpResponseException: Error parsing input
-            {statusCode=200, message=OK, headers={Date=[Sun, 26 Aug 2012 01:22:50 GMT], Transfer-Encoding=[chunked], Set-Cookie=[JSESSIONID=8A07404DF0405E46B3A748C3763B0D9F; Path=/ovisspxy; Secure], Connection=[close]}, payload=[content=true, contentMetadata=[contentDisposition=null, contentEncoding=null, contentLanguage=null, contentLength=null, contentMD5=null, contentType=text/xml;charset=UTF-8, expires=null], written=false]}
-                at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:78)
-                at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:1)
-                at com.google.common.base.Functions$FunctionComposition.apply(Functions.java:209)
-                at com.google.common.util.concurrent.Futures$3.apply(Futures.java:380)
-                at com.google.common.util.concurrent.Futures$ChainingListenableFuture.run(Futures.java:522)
-                at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
-                at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
-                at java.lang.Thread.run(Unknown Source)
-                at org.jclouds.concurrent.config.DescribingExecutorService.submit(DescribingExecutorService.java:89)
-                at org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.createNodeInGroupWithNameAndTemplate(CreateNodesWithGroupEncodedIntoNameThenAddToSet.java:170)
-                at org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.execute(CreateNodesWithGroupEncodedIntoNameThenAddToSet.java:125)
-                at org.jclouds.compute.internal.BaseComputeService.createNodesInGroup(BaseComputeService.java:213)
-                at org.jclouds.compute.internal.BaseComputeService.createNodesInGroup(BaseComputeService.java:229)
-                at org.jclouds.compute.internal.BaseComputeServiceLiveTest$1.call(BaseComputeServiceLiveTest.java:442)
-                at org.jclouds.compute.internal.BaseComputeServiceLiveTest$1.call(BaseComputeServiceLiveTest.java:1)
-                ... 3 more
-            Caused by: org.jclouds.http.HttpException: The status of Instance[UZXC0GRT-9Q988189J] is [RECONFIG_ING].
-                at org.jclouds.fujitsu.fgcp.xml.FGCPJAXBParser.fromXML(FGCPJAXBParser.java:81)
-                at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:91)
-*/        
-//    }
+//   @Override
+//   @Test(enabled = false)
+//   public void testConcurrentUseOfComputeServiceToCreateNodes() throws Exception {
+      // http://code.google.com/p/jclouds/issues/detail?id=1066
+      /*
+      1) ExecutionException on twin0-f6a:
+         java.util.concurrent.ExecutionException: org.jclouds.http.HttpResponseException: Error parsing input
+         {statusCode=200, message=OK, headers={Date=[Sun, 26 Aug 2012 01:22:50 GMT], Transfer-Encoding=[chunked], Set-Cookie=[JSESSIONID=8A07404DF0405E46B3A748C3763B0D9F; Path=/ovisspxy; Secure], Connection=[close]}, payload=[content=true, contentMetadata=[contentDisposition=null, contentEncoding=null, contentLanguage=null, contentLength=null, contentMD5=null, contentType=text/xml;charset=UTF-8, expires=null], written=false]}
+            at com.google.common.util.concurrent.AbstractFuture$Sync.getValue(AbstractFuture.java:289)
+            at com.google.common.util.concurrent.AbstractFuture$Sync.get(AbstractFuture.java:276)
+            at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:111)
+            at org.jclouds.concurrent.FutureIterables$1.run(FutureIterables.java:134)
+            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
+            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+            at java.lang.Thread.run(Unknown Source)
+         Caused by: org.jclouds.http.HttpResponseException: Error parsing input
+         {statusCode=200, message=OK, headers={Date=[Sun, 26 Aug 2012 01:22:50 GMT], Transfer-Encoding=[chunked], Set-Cookie=[JSESSIONID=8A07404DF0405E46B3A748C3763B0D9F; Path=/ovisspxy; Secure], Connection=[close]}, payload=[content=true, contentMetadata=[contentDisposition=null, contentEncoding=null, contentLanguage=null, contentLength=null, contentMD5=null, contentType=text/xml;charset=UTF-8, expires=null], written=false]}
+            at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:78)
+            at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:1)
+            at com.google.common.base.Functions$FunctionComposition.apply(Functions.java:209)
+            at com.google.common.util.concurrent.Futures$3.apply(Futures.java:380)
+            at com.google.common.util.concurrent.Futures$ChainingListenableFuture.run(Futures.java:522)
+            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
+            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
+            at java.lang.Thread.run(Unknown Source)
+            at org.jclouds.concurrent.config.DescribingExecutorService.submit(DescribingExecutorService.java:89)
+            at org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.createNodeInGroupWithNameAndTemplate(CreateNodesWithGroupEncodedIntoNameThenAddToSet.java:170)
+            at org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet.execute(CreateNodesWithGroupEncodedIntoNameThenAddToSet.java:125)
+            at org.jclouds.compute.internal.BaseComputeService.createNodesInGroup(BaseComputeService.java:213)
+            at org.jclouds.compute.internal.BaseComputeService.createNodesInGroup(BaseComputeService.java:229)
+            at org.jclouds.compute.internal.BaseComputeServiceLiveTest$1.call(BaseComputeServiceLiveTest.java:442)
+            at org.jclouds.compute.internal.BaseComputeServiceLiveTest$1.call(BaseComputeServiceLiveTest.java:1)
+            ... 3 more
+         Caused by: org.jclouds.http.HttpException: The status of Instance[UZXC0GRT-9Q988189J] is [RECONFIG_ING].
+            at org.jclouds.fujitsu.fgcp.xml.FGCPJAXBParser.fromXML(FGCPJAXBParser.java:81)
+            at org.jclouds.http.functions.ParseXMLWithJAXB.apply(ParseXMLWithJAXB.java:91)
+*/      
+//   }
 }
\ No newline at end of file
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToOperatingSystemTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToOperatingSystemTest.java
index 966ea07..2c947e5 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToOperatingSystemTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/compute/functions/DiskImageToOperatingSystemTest.java
@@ -11,7 +11,6 @@
 
 import org.jclouds.compute.domain.OperatingSystem;
 import org.jclouds.compute.domain.OsFamily;
-import org.jclouds.fujitsu.fgcp.compute.functions.DiskImageToOperatingSystem;
 import org.jclouds.fujitsu.fgcp.domain.DiskImage;
 import org.jclouds.fujitsu.fgcp.domain.DiskImage.Builder;
 import org.testng.annotations.Test;
@@ -21,143 +20,143 @@
  */
 @Test(groups = "unit", testName = "DiskImageToOperatingSystemTest")
 public class DiskImageToOperatingSystemTest {
-    // Operating Systems available JAN 2012 (taken from osName)
-    private static final List<String> operatingSystems = Arrays.asList(
-            // JP
-            "CentOS 5.6 32bit (English)",
-            "CentOS 5.6 64bit (English)",
-            "Red Hat Enterprise Linux 5.5 32bit (Japanese)",
-            "Red Hat Enterprise Linux 5.5 64bit (Japanese)",
-            "Windows Server 2003 R2 EE 32bit SP2 (日本語版) サポート付",
-            "Windows Server 2003 R2 EE 32bit SP2 (日本語版)",
-            "Windows Server 2008 R2 EE 64bit (日本語版) サポート付",
-            "Windows Server 2008 R2 EE 64bit (日本語版)",
-            "Windows Server 2008 R2 SE 64bit (日本語版)  サポート付",
-            "Windows Server 2008 R2 SE 64bit (日本語版)",
-            "Windows Server 2008 SE 32bit SP2 (日本語版) サポート付",
-            "Windows Server 2008 SE 32bit SP2 (日本語版)",
-            // AU
-            "CentOS 5.4 64bit (English)", "CentOS 5.4 32bit (English)",
-            "Windows Server 2008 R2 SE 64bit (English)",
-            "Windows Server 2008 R2 EE 64bit (English)");
+   // Operating Systems available JAN 2012 (taken from osName)
+   private static final List<String> operatingSystems = Arrays.asList(
+         // JP
+         "CentOS 5.6 32bit (English)",
+         "CentOS 5.6 64bit (English)",
+         "Red Hat Enterprise Linux 5.5 32bit (Japanese)",
+         "Red Hat Enterprise Linux 5.5 64bit (Japanese)",
+         "Windows Server 2003 R2 EE 32bit SP2 (日本語版) サポート付",
+         "Windows Server 2003 R2 EE 32bit SP2 (日本語版)",
+         "Windows Server 2008 R2 EE 64bit (日本語版) サポート付",
+         "Windows Server 2008 R2 EE 64bit (日本語版)",
+         "Windows Server 2008 R2 SE 64bit (日本語版)  サポート付",
+         "Windows Server 2008 R2 SE 64bit (日本語版)",
+         "Windows Server 2008 SE 32bit SP2 (日本語版) サポート付",
+         "Windows Server 2008 SE 32bit SP2 (日本語版)",
+         // AU
+         "CentOS 5.4 64bit (English)", "CentOS 5.4 32bit (English)",
+         "Windows Server 2008 R2 SE 64bit (English)",
+         "Windows Server 2008 R2 EE 64bit (English)");
 
-    @Test
-    public void testConversion() {
-        for (String description : operatingSystems) {
-            Builder builder = DiskImage.builder();
-            builder.osName(description);
-            builder.osType("hvm");
-            builder.creatorName("creator");
-            builder.registrant("registrant");
-            builder.description("description");
-            builder.id("ABCDEFGH");
-            DiskImage image = builder.build();
+   @Test
+   public void testConversion() {
+      for (String description : operatingSystems) {
+         Builder builder = DiskImage.builder();
+         builder.osName(description);
+         builder.osType("hvm");
+         builder.creatorName("creator");
+         builder.registrant("registrant");
+         builder.description("description");
+         builder.id("ABCDEFGH");
+         DiskImage image = builder.build();
 
-            OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+         OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-            assertNotNull(os, description);
-            assertNotNull(os.getFamily(), description);
-            assertFalse(os.getFamily().equals(OsFamily.UNRECOGNIZED),
-                    "OsFamily not recognised: " + description);
-            assertNotNull(os.getVersion(), "Version not recognised: "
-                    + description);
-            assertEquals(os.getName(), description);
-            assertEquals(os.getDescription(), description);
-            assertNotNull(os.getArch(), description);
-        }
-    }
+         assertNotNull(os, description);
+         assertNotNull(os.getFamily(), description);
+         assertFalse(os.getFamily().equals(OsFamily.UNRECOGNIZED),
+               "OsFamily not recognised: " + description);
+         assertNotNull(os.getVersion(), "Version not recognised: "
+               + description);
+         assertEquals(os.getName(), description);
+         assertEquals(os.getDescription(), description);
+         assertNotNull(os.getArch(), description);
+      }
+   }
 
-    @Test
-    public void testOsFamilyUnrecognized() {
-        DiskImage image = DiskImage.builder()
-                .osName("not a known operating system").build();
+   @Test
+   public void testOsFamilyUnrecognized() {
+      DiskImage image = DiskImage.builder()
+            .osName("not a known operating system").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-        assertNotNull(os);
-        assertEquals(os.getFamily(), OsFamily.UNRECOGNIZED);
-    }
+      assertNotNull(os);
+      assertEquals(os.getFamily(), OsFamily.UNRECOGNIZED);
+   }
 
-    @Test
-    public void test64BitsWithSpace() {
-        DiskImage image = DiskImage.builder().osName("a (64 bit) os").build();
+   @Test
+   public void test64BitsWithSpace() {
+      DiskImage image = DiskImage.builder().osName("a (64 bit) os").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-        assertNotNull(os);
-        assertTrue(os.is64Bit());
-    }
+      assertNotNull(os);
+      assertTrue(os.is64Bit());
+   }
 
-    @Test
-    public void test64BitsNoSpace() {
-        DiskImage image = DiskImage.builder().osName("a (64bit) os").build();
+   @Test
+   public void test64BitsNoSpace() {
+      DiskImage image = DiskImage.builder().osName("a (64bit) os").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-        assertNotNull(os);
-        assertTrue(os.is64Bit());
-    }
+      assertNotNull(os);
+      assertTrue(os.is64Bit());
+   }
 
-    @Test
-    public void test32BitsNoSpace() {
-        DiskImage image = DiskImage.builder().osName("a (32bit) os").build();
+   @Test
+   public void test32BitsNoSpace() {
+      DiskImage image = DiskImage.builder().osName("a (32bit) os").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-        assertNotNull(os);
-        assertFalse(os.is64Bit());
-    }
+      assertNotNull(os);
+      assertFalse(os.is64Bit());
+   }
 
-    @Test
-    public void testx64NoSpace() {
-        DiskImage image = DiskImage.builder().osName("a (x64) os").build();
+   @Test
+   public void testx64NoSpace() {
+      DiskImage image = DiskImage.builder().osName("a (x64) os").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-        assertNotNull(os);
-        assertTrue(os.is64Bit());
-    }
+      assertNotNull(os);
+      assertTrue(os.is64Bit());
+   }
 
-    @Test
-    public void testWindowsVersion() {
-        DiskImage image = DiskImage.builder()
-                .osName("Windows Server 2008 R2 SE 64 bit").build();
+   @Test
+   public void testWindowsVersion() {
+      DiskImage image = DiskImage.builder()
+            .osName("Windows Server 2008 R2 SE 64 bit").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-        assertNotNull(os);
-        assertEquals(os.getVersion(), "2008 R2 SE");
-    }
+      assertNotNull(os);
+      assertEquals(os.getVersion(), "2008 R2 SE");
+   }
 
-    @Test
-    public void testCentOSVersion() {
-        DiskImage image = DiskImage.builder()
-                .osName("CentOS 6.2 64bit (English)").build();
+   @Test
+   public void testCentOSVersion() {
+      DiskImage image = DiskImage.builder()
+            .osName("CentOS 6.2 64bit (English)").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-        assertNotNull(os);
-        assertEquals(os.getVersion(), "6.2");
-    }
+      assertNotNull(os);
+      assertEquals(os.getVersion(), "6.2");
+   }
 
-    @Test
-    public void testUnrecognizedOsVersion() {
-        DiskImage image = DiskImage.builder()
-                .osName("Windows Server 2099 (256 bit)").build();
+   @Test
+   public void testUnrecognizedOsVersion() {
+      DiskImage image = DiskImage.builder()
+            .osName("Windows Server 2099 (256 bit)").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
 
-        assertNotNull(os);
-        assertNull(os.getVersion());
-    }
+      assertNotNull(os);
+      assertNull(os.getVersion());
+   }
 
-    @Test
-    public void testOsVersionMissing() {
-        DiskImage image = DiskImage.builder().osName("asd Server").build();
+   @Test
+   public void testOsVersionMissing() {
+      DiskImage image = DiskImage.builder().osName("asd Server").build();
 
-        OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
-        assertNotNull(os);
-        assertNull(os.getVersion(), "os.getVersion(): \'" + os.getVersion()
-                + "\'");
-    }
+      OperatingSystem os = new DiskImageToOperatingSystem().apply(image);
+      assertNotNull(os);
+      assertNull(os.getVersion(), "os.getVersion(): \'" + os.getVersion()
+            + "\'");
+   }
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskApiExpectTest.java
index 953fceb..b2a0fd2 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/AdditionalDiskApiExpectTest.java
@@ -30,128 +30,128 @@
 @Test(groups = "unit", testName = "AdditionalDiskApiExpectTest", singleThreaded = true)
 public class AdditionalDiskApiExpectTest extends BaseFGCPRestApiExpectTest {
 
-    public void testGet() {
-        HttpRequest request = buildGETWithQuery("Action=GetVDiskAttributes"
-                + "&vdiskId=CONTRACT-VSYS00001-D-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVDiskAttributes-response.xml"))
-                .build();
+   public void testGet() {
+      HttpRequest request = buildGETWithQuery("Action=GetVDiskAttributes"
+            + "&vdiskId=CONTRACT-VSYS00001-D-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVDiskAttributes-response.xml"))
+            .build();
 
-        AdditionalDiskApi api = requestSendsResponse(request, response)
-                .getAdditionalDiskApi();
+      AdditionalDiskApi api = requestSendsResponse(request, response)
+            .getAdditionalDiskApi();
 
-        assertEquals(api.get("CONTRACT-VSYS00001-D-0001").getSize(), 10.0);
-    }
+      assertEquals(api.get("CONTRACT-VSYS00001-D-0001").getSize(), 10.0);
+   }
 
-    public void testGetStatus() {
-        HttpRequest request = buildGETWithQuery("Action=GetVDiskStatus"
-                + "&vdiskId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVDiskStatus-response.xml"))
-                .build();
+   public void testGetStatus() {
+      HttpRequest request = buildGETWithQuery("Action=GetVDiskStatus"
+            + "&vdiskId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVDiskStatus-response.xml"))
+            .build();
 
-        AdditionalDiskApi api = requestSendsResponse(request, response)
-                .getAdditionalDiskApi();
+      AdditionalDiskApi api = requestSendsResponse(request, response)
+            .getAdditionalDiskApi();
 
-        // api is returning STOPPED which is not a documented status. Documentation error?
-//        assertEquals(api.getStatus("CONTRACT-VSYS00001-S-0001"), VDiskStatus.STOPPED);
-    }
+      // api is returning STOPPED which is not a documented status. Documentation error?
+//      assertEquals(api.getStatus("CONTRACT-VSYS00001-S-0001"), VDiskStatus.STOPPED);
+   }
 
-    public void testUpdate() {
-        HttpRequest request = buildGETWithQuery("Action=UpdateVDiskAttribute"
-                + "&vdiskId=CONTRACT-VSYS00001-D-0001"
-                + "&attributeValue=new-name" + "&attributeName=updateName"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/UpdateVDiskAttribute-response.xml"))
-                .build();
+   public void testUpdate() {
+      HttpRequest request = buildGETWithQuery("Action=UpdateVDiskAttribute"
+            + "&vdiskId=CONTRACT-VSYS00001-D-0001"
+            + "&attributeValue=new-name" + "&attributeName=updateName"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/UpdateVDiskAttribute-response.xml"))
+            .build();
 
-        AdditionalDiskApi api = requestSendsResponse(request, response)
-                .getAdditionalDiskApi();
+      AdditionalDiskApi api = requestSendsResponse(request, response)
+            .getAdditionalDiskApi();
 
-        api.update("CONTRACT-VSYS00001-D-0001", "updateName", "new-name");
-    }
+      api.update("CONTRACT-VSYS00001-D-0001", "updateName", "new-name");
+   }
 
-    public void testDestroy() {
-        HttpRequest request = buildGETWithQuery("Action=DestroyVDisk"
-                + "&vdiskId=CONTRACT-VSYS00001-D-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/DestroyVDisk-response.xml"))
-                .build();
+   public void testDestroy() {
+      HttpRequest request = buildGETWithQuery("Action=DestroyVDisk"
+            + "&vdiskId=CONTRACT-VSYS00001-D-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/DestroyVDisk-response.xml"))
+            .build();
 
-        AdditionalDiskApi api = requestSendsResponse(request, response)
-                .getAdditionalDiskApi();
+      AdditionalDiskApi api = requestSendsResponse(request, response)
+            .getAdditionalDiskApi();
 
-        api.destroy("CONTRACT-VSYS00001-D-0001");
-    }
+      api.destroy("CONTRACT-VSYS00001-D-0001");
+   }
 
-    public void testBackup() {
-        HttpRequest request = buildGETWithQuery("Action=BackupVDisk"
-                + "&vdiskId=CONTRACT-VSYS00001-D-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/BackupVDisk-response.xml"))
-                .build();
+   public void testBackup() {
+      HttpRequest request = buildGETWithQuery("Action=BackupVDisk"
+            + "&vdiskId=CONTRACT-VSYS00001-D-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/BackupVDisk-response.xml"))
+            .build();
 
-        AdditionalDiskApi api = requestSendsResponse(request, response)
-                .getAdditionalDiskApi();
+      AdditionalDiskApi api = requestSendsResponse(request, response)
+            .getAdditionalDiskApi();
 
-        api.backup("CONTRACT-VSYS00001-D-0001");
-    }
+      api.backup("CONTRACT-VSYS00001-D-0001");
+   }
 
-    public void testRestore() {
-        HttpRequest request = buildGETWithQuery("Action=RestoreVDisk"
-                + "&vsysId=CONTRACT-VSYS00001"
-                + "&backupId=003");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/RestoreVDisk-response.xml"))
-                .build();
+   public void testRestore() {
+      HttpRequest request = buildGETWithQuery("Action=RestoreVDisk"
+            + "&vsysId=CONTRACT-VSYS00001"
+            + "&backupId=003");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/RestoreVDisk-response.xml"))
+            .build();
 
-        AdditionalDiskApi api = requestSendsResponse(request, response)
-                .getAdditionalDiskApi();
+      AdditionalDiskApi api = requestSendsResponse(request, response)
+            .getAdditionalDiskApi();
 
-        api.restore("CONTRACT-VSYS00001", "003");
-    }
+      api.restore("CONTRACT-VSYS00001", "003");
+   }
 
-    public void testDetach() {
-        HttpRequest request = buildGETWithQuery("Action=DetachVDisk"
-                + "&vdiskId=CONTRACT-VSYS00001-D-0001"
-                + "&vserverId=CONTRACT-VSYS00001-S-0006"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/DetachVDisk-response.xml"))
-                .build();
+   public void testDetach() {
+      HttpRequest request = buildGETWithQuery("Action=DetachVDisk"
+            + "&vdiskId=CONTRACT-VSYS00001-D-0001"
+            + "&vserverId=CONTRACT-VSYS00001-S-0006"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/DetachVDisk-response.xml"))
+            .build();
 
-        AdditionalDiskApi api = requestSendsResponse(request, response)
-                .getAdditionalDiskApi();
+      AdditionalDiskApi api = requestSendsResponse(request, response)
+            .getAdditionalDiskApi();
 
-        api.detach("CONTRACT-VSYS00001-D-0001", "CONTRACT-VSYS00001-S-0006");
-    }
+      api.detach("CONTRACT-VSYS00001-D-0001", "CONTRACT-VSYS00001-S-0006");
+   }
 
-    public void testDestroyBackup() {
-        HttpRequest request = buildGETWithQuery("Action=DestroyVDiskBackup"
-                + "&vsysId=CONTRACT-VSYS00001"
-                + "&backupId=003");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/DestroyVDiskBackup-response.xml"))
-                .build();
+   public void testDestroyBackup() {
+      HttpRequest request = buildGETWithQuery("Action=DestroyVDiskBackup"
+            + "&vsysId=CONTRACT-VSYS00001"
+            + "&backupId=003");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/DestroyVDiskBackup-response.xml"))
+            .build();
 
-        AdditionalDiskApi api = requestSendsResponse(request, response)
-                .getAdditionalDiskApi();
+      AdditionalDiskApi api = requestSendsResponse(request, response)
+            .getAdditionalDiskApi();
 
-        api.destroyBackup("CONTRACT-VSYS00001", "003");
-    }
+      api.destroyBackup("CONTRACT-VSYS00001", "003");
+   }
 
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BaseFGCPApiLiveTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BaseFGCPApiLiveTest.java
index 1da6e1f..0a209d3 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BaseFGCPApiLiveTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BaseFGCPApiLiveTest.java
@@ -35,50 +35,50 @@
  */
 public class BaseFGCPApiLiveTest extends BaseComputeServiceContextLiveTest {
 
-    protected RestContext<FGCPApi, FGCPAsyncApi> fgcpContext;
+   protected RestContext<FGCPApi, FGCPAsyncApi> fgcpContext;
 
-    public BaseFGCPApiLiveTest() {
-        provider = "fgcp";
-    }
+   public BaseFGCPApiLiveTest() {
+      provider = "fgcp";
+   }
 
-    @Override
-    protected Properties setupProperties() {
-        Properties overrides = super.setupProperties();
+   @Override
+   protected Properties setupProperties() {
+      Properties overrides = super.setupProperties();
 
-        String proxy = System.getenv("http_proxy");
-        if (proxy != null) {
+      String proxy = System.getenv("http_proxy");
+      if (proxy != null) {
 
-            String[] parts = proxy.split("http://|:|@");
+         String[] parts = proxy.split("http://|:|@");
 
-            overrides.setProperty(Constants.PROPERTY_PROXY_HOST,
-                    parts[parts.length - 2]);
-            overrides.setProperty(Constants.PROPERTY_PROXY_PORT,
-                    parts[parts.length - 1]);
+         overrides.setProperty(Constants.PROPERTY_PROXY_HOST,
+               parts[parts.length - 2]);
+         overrides.setProperty(Constants.PROPERTY_PROXY_PORT,
+               parts[parts.length - 1]);
 
-            if (parts.length >= 4) {
-                overrides.setProperty(Constants.PROPERTY_PROXY_USER,
-                        parts[parts.length - 4]);
-                overrides.setProperty(Constants.PROPERTY_PROXY_PASSWORD,
-                        parts[parts.length - 3]);
-            }
-        }
+         if (parts.length >= 4) {
+            overrides.setProperty(Constants.PROPERTY_PROXY_USER,
+                  parts[parts.length - 4]);
+            overrides.setProperty(Constants.PROPERTY_PROXY_PASSWORD,
+                  parts[parts.length - 3]);
+         }
+      }
 
-        // enables peer verification using the CAs bundled with the JRE (or
-        // value of javax.net.ssl.trustStore if set)
-        overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
+      // enables peer verification using the CAs bundled with the JRE (or
+      // value of javax.net.ssl.trustStore if set)
+      overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "false");
 
-        return overrides;
-    }
+      return overrides;
+   }
 
-    @BeforeGroups(groups = { "integration", "live" })
-    @Override
-    public void setupContext() {
-        super.setupContext();
-        fgcpContext = view.unwrap();
-    }
+   @BeforeGroups(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      super.setupContext();
+      fgcpContext = view.unwrap();
+   }
 
-    @Override
-    protected Module getSshModule() {
-        return new SshjSshClientModule();
-    }
+   @Override
+   protected Module getSshModule() {
+      return new SshjSshClientModule();
+   }
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BaseFGCPRestApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BaseFGCPRestApiExpectTest.java
index 2fb42da..4a90da0 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BaseFGCPRestApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BaseFGCPRestApiExpectTest.java
@@ -46,11 +46,11 @@
 public class BaseFGCPRestApiExpectTest extends
 		BaseRestClientExpectTest<FGCPApi> {
 
-    public BaseFGCPRestApiExpectTest() {
+   public BaseFGCPRestApiExpectTest() {
 		provider = "fgcp";
 
-        // self-signed dummy cert:
-        // keytool -genkey -alias test-fgcp -keyalg RSA -keysize 1024 -validity 5475 -dname "CN=localhost" -keystore jclouds-test-fgcp.p12 -storepass jcloudsjclouds -storetype pkcs12
+      // self-signed dummy cert:
+      // keytool -genkey -alias test-fgcp -keyalg RSA -keysize 1024 -validity 5475 -dname "CN=localhost" -keystore jclouds-test-fgcp.p12 -storepass jcloudsjclouds -storetype pkcs12
 		String cert = "/certs/jclouds-test-fgcp.p12";
 		URL url = this.getClass().getResource(cert);
 		assertNotNull(url, cert + " not found");
@@ -79,47 +79,47 @@
 		return new TestFGCPRestClientModule();
 	}
 
-    @Override
-    protected ProviderMetadata createProviderMetadata() {
-        return new FGCPProviderMetadata();
-    }
+   @Override
+   protected ProviderMetadata createProviderMetadata() {
+      return new FGCPProviderMetadata();
+   }
 
-    @Override
-    public Payload payloadFromResource(String resource) {
-        return super.payloadFromResource("/responses" + resource);
-    }
+   @Override
+   public Payload payloadFromResource(String resource) {
+      return super.payloadFromResource("/responses" + resource);
+   }
 
-    protected static HttpRequest buildGETWithQuery(String query) {
-        URI uri = URI.create("https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint"
-                + "?Version=2012-02-18"
-                + "&" + query
-                + "&Locale=en"
-                + "&AccessKeyId=R01ULTA5OjAwJjEyMzQ1Njc4OTAmMS4wJlNIQTF3aXRoUlNB"
-//                + "&Signature=G2rGfLAkbq0IURQfXIWYxj3BnMGbjRk4KPnZLAze3Lt4SMMRt8lkjqKvR5Cm%2BnFpDN7J6IprVCCsIrRq5BqPeXT6xtWyb6qMNds2BAr1h%2FJePGs0UosOh2tgPUMSFlZwLVjgNyrSa2zeHA3AEHjF6H1jqcWXXqfCAD4SOHaNavk%3D");
-        + "&Signature=G2rGfLAkbq0IURQfXIWYxj3BnMGbjRk4KPnZLAze3Lt4SMMRt8lkjqKvR5Cm%2BnFpDN7J6IprVCCs%0D%0AIrRq5BqPeXT6xtWyb6qMNds2BAr1h%2FJePGs0UosOh2tgPUMSFlZwLVjgNyrSa2zeHA3AEHjF6H1j%0D%0AqcWXXqfCAD4SOHaNavk%3D");
-        return HttpRequest
-                .builder()
-                .method("GET")
-                .endpoint(uri)
-                .addHeader("Accept", "text/xml")
-                .addHeader("User-Agent", "OViSS-API-CLIENT")
-                .build();
-    }
+   protected static HttpRequest buildGETWithQuery(String query) {
+      URI uri = URI.create("https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint"
+            + "?Version=2012-02-18"
+            + "&" + query
+            + "&Locale=en"
+            + "&AccessKeyId=R01ULTA5OjAwJjEyMzQ1Njc4OTAmMS4wJlNIQTF3aXRoUlNB"
+//            + "&Signature=G2rGfLAkbq0IURQfXIWYxj3BnMGbjRk4KPnZLAze3Lt4SMMRt8lkjqKvR5Cm%2BnFpDN7J6IprVCCsIrRq5BqPeXT6xtWyb6qMNds2BAr1h%2FJePGs0UosOh2tgPUMSFlZwLVjgNyrSa2zeHA3AEHjF6H1jqcWXXqfCAD4SOHaNavk%3D");
+      + "&Signature=G2rGfLAkbq0IURQfXIWYxj3BnMGbjRk4KPnZLAze3Lt4SMMRt8lkjqKvR5Cm%2BnFpDN7J6IprVCCs%0D%0AIrRq5BqPeXT6xtWyb6qMNds2BAr1h%2FJePGs0UosOh2tgPUMSFlZwLVjgNyrSa2zeHA3AEHjF6H1j%0D%0AqcWXXqfCAD4SOHaNavk%3D");
+      return HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint(uri)
+            .addHeader("Accept", "text/xml")
+            .addHeader("User-Agent", "OViSS-API-CLIENT")
+            .build();
+   }
 
-    protected HttpRequest preparePOSTForAction(String action) {
-        return HttpRequest
-                .builder()
-                .method("POST")
-                .endpoint(
-                        URI.create("https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint"))
-                .payload(
-                        payloadFromResourceWithContentType(
-                                "/" + action.toLowerCase() + "-request.xml",
-                                MediaType.TEXT_XML))
-                .headers(
-                        ImmutableMultimap.<String, String> builder()
-                                .put("Accept", "text/xml")
-                                .put("User-Agent", "OViSS-API-CLIENT").build())
-                .build();
-    }
+   protected HttpRequest preparePOSTForAction(String action) {
+      return HttpRequest
+            .builder()
+            .method("POST")
+            .endpoint(
+                  URI.create("https://api.globalcloud.fujitsu.com.au/ovissapi/endpoint"))
+            .payload(
+                  payloadFromResourceWithContentType(
+                        "/" + action.toLowerCase() + "-request.xml",
+                        MediaType.TEXT_XML))
+            .headers(
+                  ImmutableMultimap.<String, String> builder()
+                        .put("Accept", "text/xml")
+                        .put("User-Agent", "OViSS-API-CLIENT").build())
+            .build();
+   }
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerApiExpectTest.java
index acb2f16..a26b0ff 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/BuiltinServerApiExpectTest.java
@@ -18,8 +18,8 @@
  */
 package org.jclouds.fujitsu.fgcp.services;
 
-import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
 
 import java.util.Set;
 
@@ -36,180 +36,180 @@
 @Test(groups = "unit", testName = "BuiltinServerApiExpectTest", singleThreaded = true)
 public class BuiltinServerApiExpectTest extends BaseFGCPRestApiExpectTest {
 
-    public void testStart() {
-        HttpRequest request = buildGETWithQuery("Action=StartEFM"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/StartEFM-response.xml"))
-                .build();
+   public void testStart() {
+      HttpRequest request = buildGETWithQuery("Action=StartEFM"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/StartEFM-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        api.start("CONTRACT-VSYS00001-S-0001");
-    }
+      api.start("CONTRACT-VSYS00001-S-0001");
+   }
 
-    public void testStop() {
-        HttpRequest request = buildGETWithQuery("Action=StopEFM"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/StopEFM-response.xml"))
-                .build();
+   public void testStop() {
+      HttpRequest request = buildGETWithQuery("Action=StopEFM"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/StopEFM-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        api.stop("CONTRACT-VSYS00001-S-0001");
-    }
+      api.stop("CONTRACT-VSYS00001-S-0001");
+   }
 
-    public void testDestroy() {
-        HttpRequest request = buildGETWithQuery("Action=DestroyEFM"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/DestroyEFM-response.xml"))
-                .build();
+   public void testDestroy() {
+      HttpRequest request = buildGETWithQuery("Action=DestroyEFM"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/DestroyEFM-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        api.destroy("CONTRACT-VSYS00001-S-0001");
-    }
+      api.destroy("CONTRACT-VSYS00001-S-0001");
+   }
 
-    public void testGet() {
-        HttpRequest request = buildGETWithQuery("Action=GetEFMAttributes"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetEFMAttributes-response.xml"))
-                .build();
+   public void testGet() {
+      HttpRequest request = buildGETWithQuery("Action=GetEFMAttributes"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetEFMAttributes-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        assertEquals(api.get("CONTRACT-VSYS00001-S-0001").getType(), BuiltinServer.BuiltinServerType.FW);
-    }
+      assertEquals(api.get("CONTRACT-VSYS00001-S-0001").getType(), BuiltinServer.BuiltinServerType.FW);
+   }
 
 /*
-    public void testGetDetails() {
-        HttpRequest request = buildGETWithQuery("Action=GetEFMConfiguration"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetEFMConfiguration-response.xml"))
-                .build();
+   public void testGetDetails() {
+      HttpRequest request = buildGETWithQuery("Action=GetEFMConfiguration"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetEFMConfiguration-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-//        assertNotNull(api.getDetails("CONTRACT-VSYS00001-S-0001"));
-    }
+//      assertNotNull(api.getDetails("CONTRACT-VSYS00001-S-0001"));
+   }
 */
 
-    public void testGetStatus() {
-        HttpRequest request = buildGETWithQuery("Action=GetEFMStatus"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetEFMStatus-response.xml"))
-                .build();
+   public void testGetStatus() {
+      HttpRequest request = buildGETWithQuery("Action=GetEFMStatus"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetEFMStatus-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        assertEquals(api.getStatus("CONTRACT-VSYS00001-S-0001"), BuiltinServerStatus.RUNNING);
-    }
+      assertEquals(api.getStatus("CONTRACT-VSYS00001-S-0001"), BuiltinServerStatus.RUNNING);
+   }
 
-    public void testUpdate() {
-        HttpRequest request = buildGETWithQuery("Action=UpdateEFMAttribute"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&attributeValue=new%20name"
-                + "&attributeName=vserverName"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/UpdateEFMAttribute-response.xml"))
-                .build();
+   public void testUpdate() {
+      HttpRequest request = buildGETWithQuery("Action=UpdateEFMAttribute"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&attributeValue=new%20name"
+            + "&attributeName=vserverName"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/UpdateEFMAttribute-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        api.update("CONTRACT-VSYS00001-S-0001", "vserverName", "new name");
-    }
+      api.update("CONTRACT-VSYS00001-S-0001", "vserverName", "new name");
+   }
 
-    public void testBackup() {
-        HttpRequest request = buildGETWithQuery("Action=BackupEFM"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/BackupEFM-response.xml"))
-                .build();
+   public void testBackup() {
+      HttpRequest request = buildGETWithQuery("Action=BackupEFM"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/BackupEFM-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        api.backup("CONTRACT-VSYS00001-S-0001");
-    }
+      api.backup("CONTRACT-VSYS00001-S-0001");
+   }
 
-    public void testRestore() {
-        HttpRequest request = buildGETWithQuery("Action=RestoreEFM"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&backupId=003"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/RestoreEFM-response.xml"))
-                .build();
+   public void testRestore() {
+      HttpRequest request = buildGETWithQuery("Action=RestoreEFM"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&backupId=003"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/RestoreEFM-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        api.restore("CONTRACT-VSYS00001-S-0001", "003");
-    }
+      api.restore("CONTRACT-VSYS00001-S-0001", "003");
+   }
 
-    public void testListBackups() {
-        HttpRequest request = buildGETWithQuery("Action=ListEFMBackup"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/ListEFMBackup-response.xml"))
-                .build();
+   public void testListBackups() {
+      HttpRequest request = buildGETWithQuery("Action=ListEFMBackup"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/ListEFMBackup-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        Set<BuiltinServerBackup> backups = api.listBackups("CONTRACT-VSYS00001-S-0001");
-        assertNotNull(backups, "backups");
-        assertEquals(backups.size(), 2);
-        assertEquals(backups.iterator().next().getId(), "001");
-        assertEquals(backups.iterator().next().getTime(), "20121008201127");
-    }
+      Set<BuiltinServerBackup> backups = api.listBackups("CONTRACT-VSYS00001-S-0001");
+      assertNotNull(backups, "backups");
+      assertEquals(backups.size(), 2);
+      assertEquals(backups.iterator().next().getId(), "001");
+      assertEquals(backups.iterator().next().getTime(), "20121008201127");
+   }
 
-    public void testDestroyBackup() {
-        HttpRequest request = buildGETWithQuery("Action=DestroyEFMBackup"
-                + "&efmId=CONTRACT-VSYS00001-S-0001"
-                + "&backupId=003"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/DestroyEFMBackup-response.xml"))
-                .build();
+   public void testDestroyBackup() {
+      HttpRequest request = buildGETWithQuery("Action=DestroyEFMBackup"
+            + "&efmId=CONTRACT-VSYS00001-S-0001"
+            + "&backupId=003"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/DestroyEFMBackup-response.xml"))
+            .build();
 
-        BuiltinServerApi api = requestSendsResponse(request, response)
-                .getFirewallApi();
+      BuiltinServerApi api = requestSendsResponse(request, response)
+            .getFirewallApi();
 
-        api.destroyBackup("CONTRACT-VSYS00001-S-0001", "003");
-    }
+      api.destroyBackup("CONTRACT-VSYS00001-S-0001", "003");
+   }
 
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/DiskImageApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/DiskImageApiExpectTest.java
index d0ae9a0..4e0efda 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/DiskImageApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/DiskImageApiExpectTest.java
@@ -31,49 +31,49 @@
 @Test(groups = "unit", testName = "DiskImageApiExpectTest", singleThreaded = true)
 public class DiskImageApiExpectTest extends BaseFGCPRestApiExpectTest {
 
-    public void testGet() {
-        HttpRequest request = buildGETWithQuery("Action=GetDiskImageAttributes"
-                + "&diskImageId=IMG_A1B2C3_1234567890ABCD");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/GetDiskImageAttributes-response.xml"))
-                .build();
+   public void testGet() {
+      HttpRequest request = buildGETWithQuery("Action=GetDiskImageAttributes"
+            + "&diskImageId=IMG_A1B2C3_1234567890ABCD");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/GetDiskImageAttributes-response.xml"))
+            .build();
 
-        DiskImageApi api = requestSendsResponse(request, response)
-                .getDiskImageApi();
+      DiskImageApi api = requestSendsResponse(request, response)
+            .getDiskImageApi();
 
-        DiskImage image = api.get("IMG_A1B2C3_1234567890ABCD");
+      DiskImage image = api.get("IMG_A1B2C3_1234567890ABCD");
 
-        assertEquals(image.getId(), "IMG_A1B2C3_1234567890ABCD");
-        assertEquals(image.getCreatorName(), "ABCDEFGH");
-    }
+      assertEquals(image.getId(), "IMG_A1B2C3_1234567890ABCD");
+      assertEquals(image.getCreatorName(), "ABCDEFGH");
+   }
 
-    public void testUpdate() {
-        HttpRequest request = buildGETWithQuery("Action=UpdateDiskImageAttribute"
-                + "&diskImageId=IMG_A1B2C3_1234567890ABCD"
-                + "&attributeName=updateName"
-                + "&updateLcId=en"
-                + "&attributeValue=new-name");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/UpdateDiskImageAttribute-response.xml"))
-                .build();
+   public void testUpdate() {
+      HttpRequest request = buildGETWithQuery("Action=UpdateDiskImageAttribute"
+            + "&diskImageId=IMG_A1B2C3_1234567890ABCD"
+            + "&attributeName=updateName"
+            + "&updateLcId=en"
+            + "&attributeValue=new-name");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/UpdateDiskImageAttribute-response.xml"))
+            .build();
 
-        DiskImageApi api = requestSendsResponse(request, response)
-                .getDiskImageApi();
+      DiskImageApi api = requestSendsResponse(request, response)
+            .getDiskImageApi();
 
-        api.update("IMG_A1B2C3_1234567890ABCD", "en", "updateName", "new-name");
-    }
+      api.update("IMG_A1B2C3_1234567890ABCD", "en", "updateName", "new-name");
+   }
 
-    public void testDeregister() {
-        HttpRequest request = buildGETWithQuery("Action=UnregisterDiskImage"
-                + "&diskImageId=IMG_A1B2C3_1234567890ABCD");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/UnregisterDiskImage-response.xml"))
-                .build();
+   public void testDeregister() {
+      HttpRequest request = buildGETWithQuery("Action=UnregisterDiskImage"
+            + "&diskImageId=IMG_A1B2C3_1234567890ABCD");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/UnregisterDiskImage-response.xml"))
+            .build();
 
-        DiskImageApi api = requestSendsResponse(request, response)
-                .getDiskImageApi();
+      DiskImageApi api = requestSendsResponse(request, response)
+            .getDiskImageApi();
 
-        api.deregister("IMG_A1B2C3_1234567890ABCD");
-    }
+      api.deregister("IMG_A1B2C3_1234567890ABCD");
+   }
 
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressApiExpectTest.java
index 226ec07..8458fe2 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/PublicIPAddressApiExpectTest.java
@@ -33,77 +33,77 @@
 @Test(groups = "unit", testName = "PublicIPAddressApiExpectTest", singleThreaded = true)
 public class PublicIPAddressApiExpectTest extends BaseFGCPRestApiExpectTest {
 
-    public void testAttach() {
-        HttpRequest request = buildGETWithQuery("Action=AttachPublicIP"
-                + "&vsysId=CONTRACT-VSYS00001"
-                + "&publicIp=123.45.67.89");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/AttachPublicIP-response.xml"))
-                .build();
+   public void testAttach() {
+      HttpRequest request = buildGETWithQuery("Action=AttachPublicIP"
+            + "&vsysId=CONTRACT-VSYS00001"
+            + "&publicIp=123.45.67.89");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/AttachPublicIP-response.xml"))
+            .build();
 
-        PublicIPAddressApi api = requestSendsResponse(request, response)
-                .getPublicIPAddressApi();
+      PublicIPAddressApi api = requestSendsResponse(request, response)
+            .getPublicIPAddressApi();
 
-        api.attach("CONTRACT-VSYS00001", "123.45.67.89");
-    }
+      api.attach("CONTRACT-VSYS00001", "123.45.67.89");
+   }
 
-    public void testDetach() {
-        HttpRequest request = buildGETWithQuery("Action=DetachPublicIP"
-                + "&vsysId=CONTRACT-VSYS00001"
-                + "&publicIp=123.45.67.89");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/DetachPublicIP-response.xml"))
-                .build();
+   public void testDetach() {
+      HttpRequest request = buildGETWithQuery("Action=DetachPublicIP"
+            + "&vsysId=CONTRACT-VSYS00001"
+            + "&publicIp=123.45.67.89");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/DetachPublicIP-response.xml"))
+            .build();
 
-        PublicIPAddressApi api = requestSendsResponse(request, response)
-                .getPublicIPAddressApi();
+      PublicIPAddressApi api = requestSendsResponse(request, response)
+            .getPublicIPAddressApi();
 
-        api.detach("CONTRACT-VSYS00001", "123.45.67.89");
-    }
+      api.detach("CONTRACT-VSYS00001", "123.45.67.89");
+   }
 
-    public void testFree() {
-        HttpRequest request = buildGETWithQuery("Action=FreePublicIP"
-                + "&vsysId=CONTRACT-VSYS00001"
-                + "&publicIp=123.45.67.89");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/FreePublicIP-response.xml"))
-                .build();
+   public void testFree() {
+      HttpRequest request = buildGETWithQuery("Action=FreePublicIP"
+            + "&vsysId=CONTRACT-VSYS00001"
+            + "&publicIp=123.45.67.89");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/FreePublicIP-response.xml"))
+            .build();
 
-        PublicIPAddressApi api = requestSendsResponse(request, response)
-                .getPublicIPAddressApi();
+      PublicIPAddressApi api = requestSendsResponse(request, response)
+            .getPublicIPAddressApi();
 
-        api.free("CONTRACT-VSYS00001", "123.45.67.89");
-    }
+      api.free("CONTRACT-VSYS00001", "123.45.67.89");
+   }
 
-    public void testGetStatus() {
-        HttpRequest request = buildGETWithQuery("Action=GetPublicIPStatus"
-                + "&publicIp=123.45.67.89");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/GetPublicIPStatus-response.xml"))
-                .build();
+   public void testGetStatus() {
+      HttpRequest request = buildGETWithQuery("Action=GetPublicIPStatus"
+            + "&publicIp=123.45.67.89");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/GetPublicIPStatus-response.xml"))
+            .build();
 
-        PublicIPAddressApi api = requestSendsResponse(request, response)
-                .getPublicIPAddressApi();
+      PublicIPAddressApi api = requestSendsResponse(request, response)
+            .getPublicIPAddressApi();
 
-        PublicIPStatus status = api.getStatus("123.45.67.89");
-        assertEquals(status, PublicIPStatus.ATTACHED);
-    }
+      PublicIPStatus status = api.getStatus("123.45.67.89");
+      assertEquals(status, PublicIPStatus.ATTACHED);
+   }
 
-    public void testGet() {
-        HttpRequest request = buildGETWithQuery("Action=GetPublicIPAttributes"
-                + "&publicIp=123.45.67.89");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/GetPublicIPAttributes-response.xml"))
-                .build();
+   public void testGet() {
+      HttpRequest request = buildGETWithQuery("Action=GetPublicIPAttributes"
+            + "&publicIp=123.45.67.89");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/GetPublicIPAttributes-response.xml"))
+            .build();
 
-        PublicIPAddressApi api = requestSendsResponse(request, response)
-                .getPublicIPAddressApi();
+      PublicIPAddressApi api = requestSendsResponse(request, response)
+            .getPublicIPAddressApi();
 
-        PublicIP ip = api.get("123.45.67.89");
+      PublicIP ip = api.get("123.45.67.89");
 
-        assertNotNull(ip, "ip");
-        assertEquals(ip.getAddress(), "123.45.67.89");
-        assertEquals(ip.getVersion(), PublicIP.Version.IPv4);
-    }
+      assertNotNull(ip, "ip");
+      assertEquals(ip.getAddress(), "123.45.67.89");
+      assertEquals(ip.getVersion(), PublicIP.Version.IPv4);
+   }
 
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateApiExpectTest.java
index 182c13f..6b653c0 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/SystemTemplateApiExpectTest.java
@@ -18,10 +18,8 @@
  */
 package org.jclouds.fujitsu.fgcp.services;
 
-import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
-import org.jclouds.fujitsu.fgcp.domain.VSystem;
 import org.jclouds.fujitsu.fgcp.domain.VSystemDescriptor;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
@@ -33,71 +31,71 @@
 @Test(groups = "unit", testName = "SystemTemplateApiExpectTest", singleThreaded = true)
 public class SystemTemplateApiExpectTest extends BaseFGCPRestApiExpectTest {
 
-    public void testGet() {
-        HttpRequest request = buildGETWithQuery("Action=GetVSYSDescriptorConfiguration"
-                + "&vsysDescriptorId=3-tier%20Skeleton");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVSYSDescriptorConfiguration-response.xml"))
-                .build();
-        SystemTemplateApi client = requestSendsResponse(request, response)
-                .getSystemTemplateApi();
+   public void testGet() {
+      HttpRequest request = buildGETWithQuery("Action=GetVSYSDescriptorConfiguration"
+            + "&vsysDescriptorId=3-tier%20Skeleton");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVSYSDescriptorConfiguration-response.xml"))
+            .build();
+      SystemTemplateApi client = requestSendsResponse(request, response)
+            .getSystemTemplateApi();
 
-        VSystemDescriptor desc = client.get("3-tier Skeleton");
-        assertNotNull(desc, "desc");
-//        assertEquals(desc.)
-    }
+      VSystemDescriptor desc = client.get("3-tier Skeleton");
+      assertNotNull(desc, "desc");
+//      assertEquals(desc.)
+   }
 
 
-    public void testUpdate() {
-        HttpRequest request = buildGETWithQuery("Action=UpdateVSYSDescriptorAttribute"
-                + "&vsysDescriptorId=3-tier%20Skeleton" + "&attributeName=updateName"
-                + "&updateLcId=en"
-                + "&attributeValue=new-name");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/UpdateVSYSDescriptorAttribute-response.xml"))
-                .build();
+   public void testUpdate() {
+      HttpRequest request = buildGETWithQuery("Action=UpdateVSYSDescriptorAttribute"
+            + "&vsysDescriptorId=3-tier%20Skeleton" + "&attributeName=updateName"
+            + "&updateLcId=en"
+            + "&attributeValue=new-name");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/UpdateVSYSDescriptorAttribute-response.xml"))
+            .build();
 
-        SystemTemplateApi api = requestSendsResponse(request, response)
-                .getSystemTemplateApi();
+      SystemTemplateApi api = requestSendsResponse(request, response)
+            .getSystemTemplateApi();
 
-        api.update("3-tier Skeleton", "en", "updateName", "new-name");
-    }
+      api.update("3-tier Skeleton", "en", "updateName", "new-name");
+   }
 
-    public void testDeregister() {
-        HttpRequest request = buildGETWithQuery("Action=UnregisterVSYSDescriptor"
-                + "&vsysDescriptorId=3-tier%20Skeleton");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/UnregisterVSYSDescriptor-response.xml"))
-                .build();
+   public void testDeregister() {
+      HttpRequest request = buildGETWithQuery("Action=UnregisterVSYSDescriptor"
+            + "&vsysDescriptorId=3-tier%20Skeleton");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/UnregisterVSYSDescriptor-response.xml"))
+            .build();
 
-        SystemTemplateApi api = requestSendsResponse(request, response)
-                .getSystemTemplateApi();
+      SystemTemplateApi api = requestSendsResponse(request, response)
+            .getSystemTemplateApi();
 
-        api.deregister("3-tier Skeleton");
-    }
+      api.deregister("3-tier Skeleton");
+   }
 
-    public void testDeregisterPrivateTemplate() {
-        HttpRequest request = buildGETWithQuery("Action=UnregisterPrivateVSYSDescriptor"
-                + "&vsysDescriptorId=3-tier%20Skeleton");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/UnregisterPrivateVSYSDescriptor-response.xml"))
-                .build();
+   public void testDeregisterPrivateTemplate() {
+      HttpRequest request = buildGETWithQuery("Action=UnregisterPrivateVSYSDescriptor"
+            + "&vsysDescriptorId=3-tier%20Skeleton");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/UnregisterPrivateVSYSDescriptor-response.xml"))
+            .build();
 
-        SystemTemplateApi api = requestSendsResponse(request, response)
-                .getSystemTemplateApi();
+      SystemTemplateApi api = requestSendsResponse(request, response)
+            .getSystemTemplateApi();
 
-        api.deregisterPrivateTemplate("3-tier Skeleton");
-    }
+      api.deregisterPrivateTemplate("3-tier Skeleton");
+   }
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApiExpectTest.java
index 277a449..32ae3ad 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApiExpectTest.java
@@ -41,166 +41,166 @@
 @Test(groups = "unit", testName = "VirtualDCApiExpectTest", singleThreaded = true)
 public class VirtualDCApiExpectTest extends BaseFGCPRestApiExpectTest {
 
-    public void testListVirtualSystems() {
-        HttpRequest request = buildGETWithQuery("Action=ListVSYS");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/ListVSYS-response.xml"))
-                .build();
+   public void testListVirtualSystems() {
+      HttpRequest request = buildGETWithQuery("Action=ListVSYS");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/ListVSYS-response.xml"))
+            .build();
 
-        VirtualDCApi api = requestSendsResponse(request, response).getVirtualDCApi();
+      VirtualDCApi api = requestSendsResponse(request, response).getVirtualDCApi();
 
-        Set<VSystem> vsysSet = api.listVirtualSystems();
-        assertEquals(vsysSet.size(), 2);
-    }
+      Set<VSystem> vsysSet = api.listVirtualSystems();
+      assertEquals(vsysSet.size(), 2);
+   }
 
-    public void testCreateVirtualSystem() {
-        HttpRequest request = buildGETWithQuery("Action=CreateVSYS&vsysDescriptorId=myDescId&vsysName=myVSYS");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/CreateVSYS-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testCreateVirtualSystem() {
+      HttpRequest request = buildGETWithQuery("Action=CreateVSYS&vsysDescriptorId=myDescId&vsysName=myVSYS");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/CreateVSYS-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        String vsysId = api.createVirtualSystem("myDescId", "myVSYS");
-        assertEquals(vsysId, "CONTRACT-VSYS00001", "vsysId: " + vsysId);
-    }
+      String vsysId = api.createVirtualSystem("myDescId", "myVSYS");
+      assertEquals(vsysId, "CONTRACT-VSYS00001", "vsysId: " + vsysId);
+   }
 
 
-    public void testListServerTypes() {
-        HttpRequest request = buildGETWithQuery("Action=ListServerType&diskImageId=dummy");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/ListServerType-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testListServerTypes() {
+      HttpRequest request = buildGETWithQuery("Action=ListServerType&diskImageId=dummy");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/ListServerType-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        Set<ServerType> serverTypes = api.listServerTypes();
-        assertNotNull(serverTypes, "serverTypes");
-        assertEquals(serverTypes.size(), 4,
-                "Unexpected number of server types: " + serverTypes.size());
-    }
+      Set<ServerType> serverTypes = api.listServerTypes();
+      assertNotNull(serverTypes, "serverTypes");
+      assertEquals(serverTypes.size(), 4,
+            "Unexpected number of server types: " + serverTypes.size());
+   }
 
-    public void testListPublicIPs() {
-        HttpRequest request = buildGETWithQuery("Action=ListPublicIP");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/ListPublicIP-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testListPublicIPs() {
+      HttpRequest request = buildGETWithQuery("Action=ListPublicIP");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/ListPublicIP-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        Map<PublicIP, String> ips = api.listPublicIPs();
+      Map<PublicIP, String> ips = api.listPublicIPs();
 
-        assertNotNull(ips, "ips");
-        assertEquals(ips.size(), 2, "Unexpected number of ips: " + ips.size());
-        assertEquals(ips.keySet().size(), 2, "Unexpected number of ips: " + ips.size());
-        assertTrue(ips.containsValue("ABCDEFGH-A123B456CE"), "missing system id");
-        assertEquals(ips.keySet().iterator().next().getVersion(), PublicIP.Version.IPv4);
-    }
+      assertNotNull(ips, "ips");
+      assertEquals(ips.size(), 2, "Unexpected number of ips: " + ips.size());
+      assertEquals(ips.keySet().size(), 2, "Unexpected number of ips: " + ips.size());
+      assertTrue(ips.containsValue("ABCDEFGH-A123B456CE"), "missing system id");
+      assertEquals(ips.keySet().iterator().next().getVersion(), PublicIP.Version.IPv4);
+   }
 
-    public void testListDiskImages() {
-        HttpRequest request = buildGETWithQuery("Action=ListDiskImage");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/ListDiskImages-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testListDiskImages() {
+      HttpRequest request = buildGETWithQuery("Action=ListDiskImage");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/ListDiskImages-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        Set<DiskImage> images = api.listDiskImages();
+      Set<DiskImage> images = api.listDiskImages();
 
-        assertNotNull(images, "images");
-        assertTrue(images.size() > 5, "Unexpected number of images: " + images.size());
-    }
+      assertNotNull(images, "images");
+      assertTrue(images.size() > 5, "Unexpected number of images: " + images.size());
+   }
 
-    public void testListDiskImage() {
-        HttpRequest request = buildGETWithQuery("Action=ListDiskImage&vsysDescriptorId=IMG_A1B2C3_1234567890ABCD");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/ListDiskImage-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testListDiskImage() {
+      HttpRequest request = buildGETWithQuery("Action=ListDiskImage&vsysDescriptorId=IMG_A1B2C3_1234567890ABCD");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/ListDiskImage-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        Set<DiskImage> images = api.listDiskImages(null, "IMG_A1B2C3_1234567890ABCD");
+      Set<DiskImage> images = api.listDiskImages(null, "IMG_A1B2C3_1234567890ABCD");
 
-        assertNotNull(images, "images");
-        assertTrue(images.size() == 1, "Unexpected number of images: " + images.size());
-    }
+      assertNotNull(images, "images");
+      assertTrue(images.size() == 1, "Unexpected number of images: " + images.size());
+   }
 
-    public void testGetAddressRange() {
-        HttpRequest request = buildGETWithQuery("Action=GetAddressRange");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/GetAddressRange-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testGetAddressRange() {
+      HttpRequest request = buildGETWithQuery("Action=GetAddressRange");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/GetAddressRange-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        Set<AddressRange> range = api.getAddressRange();
-        assertNotNull(range);
-        assertEquals(range.size(), 1);
-    }
+      Set<AddressRange> range = api.getAddressRange();
+      assertNotNull(range);
+      assertEquals(range.size(), 1);
+   }
 
-    public void testAddAddressRange() {
-        HttpRequest request = buildGETWithQuery("Action=AddAddressRange"
-                + "&pipFrom=192.168.0.0"
-                + "&pipTo=192.168.30.0");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/AddAddressRange-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testAddAddressRange() {
+      HttpRequest request = buildGETWithQuery("Action=AddAddressRange"
+            + "&pipFrom=192.168.0.0"
+            + "&pipTo=192.168.30.0");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/AddAddressRange-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        api.addAddressRange("192.168.0.0", "192.168.30.0");
-    }
+      api.addAddressRange("192.168.0.0", "192.168.30.0");
+   }
 
-    public void testDeleteAddressRange() {
-        HttpRequest request = buildGETWithQuery("Action=DeleteAddressRange"
-                + "&pipFrom=192.168.0.0"
-                + "&pipTo=192.168.30.0");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/DeleteAddressRange-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testDeleteAddressRange() {
+      HttpRequest request = buildGETWithQuery("Action=DeleteAddressRange"
+            + "&pipFrom=192.168.0.0"
+            + "&pipTo=192.168.30.0");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/DeleteAddressRange-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        api.deleteAddressRange("192.168.0.0", "192.168.30.0");
-    }
+      api.deleteAddressRange("192.168.0.0", "192.168.30.0");
+   }
 
-    public void testCreateAddressPool() {
-        HttpRequest request = buildGETWithQuery("Action=CreateAddressPool"
-                + "&pipFrom=192.168.0.0"
-                + "&pipTo=192.168.30.0");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/CreateAddressPool-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testCreateAddressPool() {
+      HttpRequest request = buildGETWithQuery("Action=CreateAddressPool"
+            + "&pipFrom=192.168.0.0"
+            + "&pipTo=192.168.30.0");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/CreateAddressPool-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        api.createAddressPool("192.168.0.0", "192.168.30.0");
-    }
+      api.createAddressPool("192.168.0.0", "192.168.30.0");
+   }
 
-    public void testGetEventLog() {
-        HttpRequest request = buildGETWithQuery("Action=GetEventLog");
-        HttpResponse response = HttpResponse.builder()
-                .statusCode(200)
-                .payload(payloadFromResource("/GetEventLog-response.xml"))
-                .build();
-        VirtualDCApi api = requestSendsResponse(request, response)
-                .getVirtualDCApi();
+   public void testGetEventLog() {
+      HttpRequest request = buildGETWithQuery("Action=GetEventLog");
+      HttpResponse response = HttpResponse.builder()
+            .statusCode(200)
+            .payload(payloadFromResource("/GetEventLog-response.xml"))
+            .build();
+      VirtualDCApi api = requestSendsResponse(request, response)
+            .getVirtualDCApi();
 
-        Set<EventLog> logs = api.getEventLogs();
-        assertNotNull(logs);
-        //TODO: get one with several
-//        assertEquals(logs.size(), 1);
-    }
+      Set<EventLog> logs = api.getEventLogs();
+      assertNotNull(logs);
+      //TODO: get one with several
+//      assertEquals(logs.size(), 1);
+   }
 
 
 
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApiLiveTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApiLiveTest.java
index 0e873ed..16a5191 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApiLiveTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualDCApiLiveTest.java
@@ -34,43 +34,43 @@
 @Test(groups = "live", enabled = true, singleThreaded = true, testName = "VirtualDCApiLiveTest")
 public class VirtualDCApiLiveTest extends BaseFGCPApiLiveTest {
 
-    private VirtualDCApi api;
+   private VirtualDCApi api;
 
-    @BeforeGroups(groups = { "live" })
-    public void setupContext() {
-        super.setupContext();
-        api = fgcpContext.getApi().getVirtualDCApi();
-    }
+   @BeforeGroups(groups = { "live" })
+   public void setupContext() {
+      super.setupContext();
+      api = fgcpContext.getApi().getVirtualDCApi();
+   }
 
-    public void testListVirtualSystems() {
-/*        Properties overrides = setupProperties();
-        RestContext<FGCPClient, FGCPAsyncClientTest> context = new RestContextFactory().createContext(provider, ImmutableSet.<Module> of(new Log4JLoggingModule()),
-                overrides);*/
+   public void testListVirtualSystems() {
+/*      Properties overrides = setupProperties();
+      RestContext<FGCPClient, FGCPAsyncClientTest> context = new RestContextFactory().createContext(provider, ImmutableSet.<Module> of(new Log4JLoggingModule()),
+            overrides);*/
 
-        Set<VSystem> vsysSet = api.listVirtualSystems();
-        assertNotNull(vsysSet, "vsysSet");
-        assertTrue(vsysSet.size() > 0, "vsysSet.size() should be greater than 0");
-        for (VSystem vsys : vsysSet) {
-            System.out.println(vsys);
-        }
-    }
+      Set<VSystem> vsysSet = api.listVirtualSystems();
+      assertNotNull(vsysSet, "vsysSet");
+      assertTrue(vsysSet.size() > 0, "vsysSet.size() should be greater than 0");
+      for (VSystem vsys : vsysSet) {
+         System.out.println(vsys);
+      }
+   }
 
-/*    public void testCreateVirtualSystem() {
-        String vsysId = api.createVirtualSystem("abc", "def");
+/*   public void testCreateVirtualSystem() {
+      String vsysId = api.createVirtualSystem("abc", "def");
 
-        assertNotNull(vsysId, "vsysId");
-        assertFalse(vsysId.equals(""), "vsysId is empty (\"\")");
-        System.out.println("vsysId: " + vsysId);
-    }*/
+      assertNotNull(vsysId, "vsysId");
+      assertFalse(vsysId.equals(""), "vsysId is empty (\"\")");
+      System.out.println("vsysId: " + vsysId);
+   }*/
 
-    public void testListServerTypes() {
-        Set<ServerType> serverTypes = api.listServerTypes();
+   public void testListServerTypes() {
+      Set<ServerType> serverTypes = api.listServerTypes();
 
-        assertNotNull(serverTypes, "serverTypes");
-        assertTrue(serverTypes.size() == 4, "serverTypes.size should return 4, not " + serverTypes.size());
+      assertNotNull(serverTypes, "serverTypes");
+      assertTrue(serverTypes.size() == 4, "serverTypes.size should return 4, not " + serverTypes.size());
 
-//        System.out.println("listServerTypes: " + serverTypes);
-    }
+//      System.out.println("listServerTypes: " + serverTypes);
+   }
 
 
 
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualServerApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualServerApiExpectTest.java
index 198993c..b6e4ec7 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualServerApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualServerApiExpectTest.java
@@ -18,8 +18,8 @@
  */
 package org.jclouds.fujitsu.fgcp.services;
 
-import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.Assert.assertEquals;
+import static org.testng.AssertJUnit.assertNotNull;
 
 import org.jclouds.fujitsu.fgcp.domain.VServerStatus;
 import org.jclouds.fujitsu.fgcp.domain.VServerWithDetails;
@@ -33,189 +33,189 @@
 @Test(groups = "unit", testName = "VirtualServerApiExpectTest", singleThreaded = true)
 public class VirtualServerApiExpectTest extends BaseFGCPRestApiExpectTest {
 
-    public void testStart() {
-        HttpRequest request = buildGETWithQuery("Action=StartVServer"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/StartVServer-response.xml"))
-                .build();
+   public void testStart() {
+      HttpRequest request = buildGETWithQuery("Action=StartVServer"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/StartVServer-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        api.start("CONTRACT-VSYS00001-S-0005");
-    }
+      api.start("CONTRACT-VSYS00001-S-0005");
+   }
 
-    public void testStop() {
-        HttpRequest request = buildGETWithQuery("Action=StopVServer"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/StopVServer-response.xml"))
-                .build();
+   public void testStop() {
+      HttpRequest request = buildGETWithQuery("Action=StopVServer"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/StopVServer-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        api.stop("CONTRACT-VSYS00001-S-0005");
-    }
+      api.stop("CONTRACT-VSYS00001-S-0005");
+   }
 
-    public void testStopForcefully() {
-        HttpRequest request = buildGETWithQuery("Action=StopVServer"
-                + "&force=true"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/StopVServer-response.xml"))
-                .build();
+   public void testStopForcefully() {
+      HttpRequest request = buildGETWithQuery("Action=StopVServer"
+            + "&force=true"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/StopVServer-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        api.stopForcefully("CONTRACT-VSYS00001-S-0005");
-    }
+      api.stopForcefully("CONTRACT-VSYS00001-S-0005");
+   }
 
-    public void testDestroy() {
-        HttpRequest request = buildGETWithQuery("Action=DestroyVServer"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/DestroyVServer-response.xml"))
-                .build();
+   public void testDestroy() {
+      HttpRequest request = buildGETWithQuery("Action=DestroyVServer"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/DestroyVServer-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        api.destroy("CONTRACT-VSYS00001-S-0005");
-    }
+      api.destroy("CONTRACT-VSYS00001-S-0005");
+   }
 
-    public void testGet() {
-        HttpRequest request = buildGETWithQuery("Action=GetVServerAttributes"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVServerAttributes-response.xml"))
-                .build();
+   public void testGet() {
+      HttpRequest request = buildGETWithQuery("Action=GetVServerAttributes"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVServerAttributes-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        assertNotNull(api.get("CONTRACT-VSYS00001-S-0005"));
-    }
+      assertNotNull(api.get("CONTRACT-VSYS00001-S-0005"));
+   }
 
-    public void testGetDetails() {
-        HttpRequest request = buildGETWithQuery("Action=GetVServerConfiguration"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVServerConfiguration-response.xml"))
-                .build();
+   public void testGetDetails() {
+      HttpRequest request = buildGETWithQuery("Action=GetVServerConfiguration"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVServerConfiguration-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        VServerWithDetails server = api.getDetails("CONTRACT-VSYS00001-S-0005");
-        assertNotNull(server);
-        assertEquals(server.getId(), "CONTRACT-VSYS00001-S-0005");
-        assertEquals(server.getVnics().iterator().next().getNicNo(), 0);
-        assertEquals(server.getVnics().iterator().next().getPrivateIp(), "192.168.4.13");
-        assertEquals(server.getVnics().iterator().next().getNetworkId(), "CONTRACT-VSYS00001-N-DMZ");
-        assertEquals(server.getImage().getId(), "IMG_A1B2C3_1234567890ABCD");
-        assertEquals(server.getImage().getSysvolSize(), 10.0f);
-    }
+      VServerWithDetails server = api.getDetails("CONTRACT-VSYS00001-S-0005");
+      assertNotNull(server);
+      assertEquals(server.getId(), "CONTRACT-VSYS00001-S-0005");
+      assertEquals(server.getVnics().iterator().next().getNicNo(), 0);
+      assertEquals(server.getVnics().iterator().next().getPrivateIp(), "192.168.4.13");
+      assertEquals(server.getVnics().iterator().next().getNetworkId(), "CONTRACT-VSYS00001-N-DMZ");
+      assertEquals(server.getImage().getId(), "IMG_A1B2C3_1234567890ABCD");
+      assertEquals(server.getImage().getSysvolSize(), 10.0f);
+   }
 
-    public void testGetStatus() {
-        HttpRequest request = buildGETWithQuery("Action=GetVServerStatus"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVServerStatus-response.xml"))
-                .build();
+   public void testGetStatus() {
+      HttpRequest request = buildGETWithQuery("Action=GetVServerStatus"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVServerStatus-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        assertEquals(api.getStatus("CONTRACT-VSYS00001-S-0005"), VServerStatus.STOPPED);
-    }
+      assertEquals(api.getStatus("CONTRACT-VSYS00001-S-0005"), VServerStatus.STOPPED);
+   }
 
-    public void testInitialPassword() {
-        HttpRequest request = buildGETWithQuery("Action=GetVServerInitialPassword"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVServerInitialPassword-response.xml"))
-                .build();
+   public void testInitialPassword() {
+      HttpRequest request = buildGETWithQuery("Action=GetVServerInitialPassword"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVServerInitialPassword-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        assertEquals(api.getInitialPassword("CONTRACT-VSYS00001-S-0005"), "mySecretpwd1");
-    }
+      assertEquals(api.getInitialPassword("CONTRACT-VSYS00001-S-0005"), "mySecretpwd1");
+   }
 
-    public void testUpdate() {
-        HttpRequest request = buildGETWithQuery("Action=UpdateVServerAttribute"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&attributeValue=new%20name"
-                + "&attributeName=vserverName"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/UpdateVServerAttribute-response.xml"))
-                .build();
+   public void testUpdate() {
+      HttpRequest request = buildGETWithQuery("Action=UpdateVServerAttribute"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&attributeValue=new%20name"
+            + "&attributeName=vserverName"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/UpdateVServerAttribute-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        api.update("CONTRACT-VSYS00001-S-0005", "vserverName", "new name");
-    }
+      api.update("CONTRACT-VSYS00001-S-0005", "vserverName", "new name");
+   }
 
-    public void testAttachDisk() {
-        HttpRequest request = buildGETWithQuery("Action=AttachVDisk"
-                + "&vserverId=CONTRACT-VSYS00001-S-0005"
-                + "&vdiskId=CONTRACT-VSYS00001-D-0001"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/AttachVDisk-response.xml"))
-                .build();
+   public void testAttachDisk() {
+      HttpRequest request = buildGETWithQuery("Action=AttachVDisk"
+            + "&vserverId=CONTRACT-VSYS00001-S-0005"
+            + "&vdiskId=CONTRACT-VSYS00001-D-0001"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/AttachVDisk-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        api.attachDisk("CONTRACT-VSYS00001-S-0005", "CONTRACT-VSYS00001-D-0001");
-    }
+      api.attachDisk("CONTRACT-VSYS00001-S-0005", "CONTRACT-VSYS00001-D-0001");
+   }
 
-/*    public void testGetPerformanceInformation() {
-        HttpRequest request = buildGETWithQuery("Action=GetPerformanceInformation"
-                + "&serverId=CONTRACT-VSYS00001-S-0005"
-                + "&interval=10minute"
-                + "&vsysId=CONTRACT-VSYS00001");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetPerformanceInformation-response.xml"))
-                .build();
+/*   public void testGetPerformanceInformation() {
+      HttpRequest request = buildGETWithQuery("Action=GetPerformanceInformation"
+            + "&serverId=CONTRACT-VSYS00001-S-0005"
+            + "&interval=10minute"
+            + "&vsysId=CONTRACT-VSYS00001");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetPerformanceInformation-response.xml"))
+            .build();
 
-        VirtualServerApi api = requestSendsResponse(request, response)
-                .getVirtualServerApi();
+      VirtualServerApi api = requestSendsResponse(request, response)
+            .getVirtualServerApi();
 
-        assertNotNull(api.getPerformanceInformation(
-                "CONTRACT-VSYS00001-S-0005", "10minute"));
-    }
+      assertNotNull(api.getPerformanceInformation(
+            "CONTRACT-VSYS00001-S-0005", "10minute"));
+   }
 */
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemApiExpectTest.java b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemApiExpectTest.java
index 31aaed1..79fc009 100644
--- a/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemApiExpectTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/fujitsu/fgcp/services/VirtualSystemApiExpectTest.java
@@ -40,220 +40,220 @@
 @Test(groups = "unit", testName = "VirtualSystemApiExpectTest", singleThreaded = true)
 public class VirtualSystemApiExpectTest extends BaseFGCPRestApiExpectTest {
 
-    public void testGet() {
-        HttpRequest request = buildGETWithQuery("Action=GetVSYSAttributes&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVSYSAttributes-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testGet() {
+      HttpRequest request = buildGETWithQuery("Action=GetVSYSAttributes&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVSYSAttributes-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        VSystem system = api.get("ABCDEFGH-A123B456CE");
-        assertNotNull(system, "system");
-    }
+      VSystem system = api.get("ABCDEFGH-A123B456CE");
+      assertNotNull(system, "system");
+   }
 
-    public void testGetDetails() {
-        HttpRequest request = buildGETWithQuery("Action=GetVSYSConfiguration&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/GetVSYSConfiguration-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testGetDetails() {
+      HttpRequest request = buildGETWithQuery("Action=GetVSYSConfiguration&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/GetVSYSConfiguration-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        VSystem system = api.getDetails("ABCDEFGH-A123B456CE");
-        assertNotNull(system, "system");
-    }
+      VSystem system = api.getDetails("ABCDEFGH-A123B456CE");
+      assertNotNull(system, "system");
+   }
 
-    public void testGetStatus() {
-        HttpRequest request = buildGETWithQuery("Action=GetVSYSStatus"
-                + "&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse.builder().statusCode(200)
-                .payload(payloadFromResource("/GetVSYSStatus-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testGetStatus() {
+      HttpRequest request = buildGETWithQuery("Action=GetVSYSStatus"
+            + "&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/GetVSYSStatus-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        assertEquals(api.getStatus("ABCDEFGH-A123B456CE"), VSystemStatus.NORMAL);
-    }
+      assertEquals(api.getStatus("ABCDEFGH-A123B456CE"), VSystemStatus.NORMAL);
+   }
 
-    public void testUpdate() {
-        HttpRequest request = buildGETWithQuery("Action=UpdateVSYSAttribute"
-                + "&vsysId=ABCDEFGH-A123B456CE" + "&attributeValue=new-name"
-                + "&attributeName=updateName");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/UpdateVDiskAttribute-response.xml"))
-                .build();
+   public void testUpdate() {
+      HttpRequest request = buildGETWithQuery("Action=UpdateVSYSAttribute"
+            + "&vsysId=ABCDEFGH-A123B456CE" + "&attributeValue=new-name"
+            + "&attributeName=updateName");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/UpdateVDiskAttribute-response.xml"))
+            .build();
 
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        api.update("ABCDEFGH-A123B456CE", "updateName", "new-name");
-    }
+      api.update("ABCDEFGH-A123B456CE", "updateName", "new-name");
+   }
 
-    public void testListPublicIPs() {
-        HttpRequest request = buildGETWithQuery("Action=ListPublicIP"
-                + "&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/ListPublicIP_one_vsys-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testListPublicIPs() {
+      HttpRequest request = buildGETWithQuery("Action=ListPublicIP"
+            + "&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/ListPublicIP_one_vsys-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        Set<PublicIP> ips = api.listPublicIPs("ABCDEFGH-A123B456CE");
-        assertNotNull(ips, "ips");
-        assertTrue(ips.size() == 2, "Unexpected number of ips: " + ips.size());
-        assertEquals(ips.iterator().next().getVersion(), PublicIP.Version.IPv4);
-    }
+      Set<PublicIP> ips = api.listPublicIPs("ABCDEFGH-A123B456CE");
+      assertNotNull(ips, "ips");
+      assertTrue(ips.size() == 2, "Unexpected number of ips: " + ips.size());
+      assertEquals(ips.iterator().next().getVersion(), PublicIP.Version.IPv4);
+   }
 
-    public void testListServers() {
-        HttpRequest request = buildGETWithQuery("Action=ListVServer"
-                + "&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/ListVServer-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testListServers() {
+      HttpRequest request = buildGETWithQuery("Action=ListVServer"
+            + "&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/ListVServer-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        Set<VServer> servers = api.listServers("ABCDEFGH-A123B456CE");
-        assertNotNull(servers, "servers");
-        assertEquals(servers.size(), 2);
-    }
+      Set<VServer> servers = api.listServers("ABCDEFGH-A123B456CE");
+      assertNotNull(servers, "servers");
+      assertEquals(servers.size(), 2);
+   }
 
-    public void testDisks() {
-        HttpRequest request = buildGETWithQuery("Action=ListVDisk"
-                + "&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/ListVDisk-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testDisks() {
+      HttpRequest request = buildGETWithQuery("Action=ListVDisk"
+            + "&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/ListVDisk-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        Set<VDisk> disks = api.listDisks("ABCDEFGH-A123B456CE");
-        assertNotNull(disks, "disks");
-        assertEquals(disks.size(), 1);
-    }
+      Set<VDisk> disks = api.listDisks("ABCDEFGH-A123B456CE");
+      assertNotNull(disks, "disks");
+      assertEquals(disks.size(), 1);
+   }
 
-    public void testListBuiltinServers() {
-        HttpRequest request = buildGETWithQuery("Action=ListEFM"
-                + "&vsysId=ABCDEFGH-A123B456CE" + "&efmType=FW");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/ListEFM-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testListBuiltinServers() {
+      HttpRequest request = buildGETWithQuery("Action=ListEFM"
+            + "&vsysId=ABCDEFGH-A123B456CE" + "&efmType=FW");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/ListEFM-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        Set<BuiltinServer> fws = api.listBuiltinServers("ABCDEFGH-A123B456CE", "FW");
-        assertNotNull(fws, "fws");
-        assertEquals(fws.size(), 1);
-    }
+      Set<BuiltinServer> fws = api.listBuiltinServers("ABCDEFGH-A123B456CE", "FW");
+      assertNotNull(fws, "fws");
+      assertEquals(fws.size(), 1);
+   }
 
-    public void testAllocatePublicIP() {
-        HttpRequest request = buildGETWithQuery("Action=AllocatePublicIP&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/AllocatePublicIP-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testAllocatePublicIP() {
+      HttpRequest request = buildGETWithQuery("Action=AllocatePublicIP&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/AllocatePublicIP-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        api.allocatePublicIP("ABCDEFGH-A123B456CE");
-    }
+      api.allocatePublicIP("ABCDEFGH-A123B456CE");
+   }
 
-    public void testCreateBuiltinServer() {
-        HttpRequest request = buildGETWithQuery("Action=CreateEFM"
-                + "&efmType=SLB"
-                + "&efmName=web%20load%20balancer"
-                + "&networkId=ABCDEFGH-A123B456CE-N-DMZ"
-                + "&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/CreateEFM-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testCreateBuiltinServer() {
+      HttpRequest request = buildGETWithQuery("Action=CreateEFM"
+            + "&efmType=SLB"
+            + "&efmName=web%20load%20balancer"
+            + "&networkId=ABCDEFGH-A123B456CE-N-DMZ"
+            + "&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/CreateEFM-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        String id = api.createBuiltinServer("web load balancer",
-                "ABCDEFGH-A123B456CE-N-DMZ");
-        assertEquals(id, "CONTRACT-EFM00001");
-    }
+      String id = api.createBuiltinServer("web load balancer",
+            "ABCDEFGH-A123B456CE-N-DMZ");
+      assertEquals(id, "CONTRACT-EFM00001");
+   }
 
-    public void testCreateServer() {
-        HttpRequest request = buildGETWithQuery("Action=CreateVServer"
-                + "&vserverName=vm1"
-                + "&diskImageId=IMG_A1B2C3_1234567890ABCD"
-                + "&vserverType=economy"
-                + "&networkId=ABCDEFGH-A123B456CE-N-DMZ"
-                + "&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/CreateVServer-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testCreateServer() {
+      HttpRequest request = buildGETWithQuery("Action=CreateVServer"
+            + "&vserverName=vm1"
+            + "&diskImageId=IMG_A1B2C3_1234567890ABCD"
+            + "&vserverType=economy"
+            + "&networkId=ABCDEFGH-A123B456CE-N-DMZ"
+            + "&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/CreateVServer-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        String id = api.createServer("vm1", "economy", "IMG_A1B2C3_1234567890ABCD",
-                "ABCDEFGH-A123B456CE-N-DMZ");
-        assertEquals(id, "ABCDEFGH-A123B456CE-S-0007");
-    }
+      String id = api.createServer("vm1", "economy", "IMG_A1B2C3_1234567890ABCD",
+            "ABCDEFGH-A123B456CE-N-DMZ");
+      assertEquals(id, "ABCDEFGH-A123B456CE-S-0007");
+   }
 
-    public void testCreateDisk() {
-        HttpRequest request = buildGETWithQuery("Action=CreateVDisk"
-                + "&vsysId=ABCDEFGH-A123B456CE"
-                + "&size=10"
-                + "&vdiskName=disk1");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/CreateVDisk-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testCreateDisk() {
+      HttpRequest request = buildGETWithQuery("Action=CreateVDisk"
+            + "&vsysId=ABCDEFGH-A123B456CE"
+            + "&size=10"
+            + "&vdiskName=disk1");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/CreateVDisk-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        String id = api.createDisk("ABCDEFGH-A123B456CE", "disk1", 10);
-        assertEquals(id, "ABCDEFGH-A123B456CE-S-0006");
-    }
+      String id = api.createDisk("ABCDEFGH-A123B456CE", "disk1", 10);
+      assertEquals(id, "ABCDEFGH-A123B456CE-S-0006");
+   }
 
 /*
-    public void testRegisterAsPrivateImage() {
-        HttpRequest request = buildGETWithQuery("Action=AllocatePublicIP&vsysId=ABCDEFGH-A123B456CE");
-        HttpResponse response = HttpResponse
-                .builder()
-                .statusCode(200)
-                .payload(
-                        payloadFromResource("/AllocatePublicIP-response.xml"))
-                .build();
-        VirtualSystemApi api = requestSendsResponse(request, response)
-                .getVirtualSystemApi();
+   public void testRegisterAsPrivateImage() {
+      HttpRequest request = buildGETWithQuery("Action=AllocatePublicIP&vsysId=ABCDEFGH-A123B456CE");
+      HttpResponse response = HttpResponse
+            .builder()
+            .statusCode(200)
+            .payload(
+                  payloadFromResource("/AllocatePublicIP-response.xml"))
+            .build();
+      VirtualSystemApi api = requestSendsResponse(request, response)
+            .getVirtualSystemApi();
 
-        api.registerAsPrivateVSYSDescriptor("ABCDEFGH-A123B456CE");
-    }
+      api.registerAsPrivateVSYSDescriptor("ABCDEFGH-A123B456CE");
+   }
 */
 }
diff --git a/labs/fgcp/src/test/java/org/jclouds/http/internal/HttpInternalsLiveTest.java b/labs/fgcp/src/test/java/org/jclouds/http/internal/HttpInternalsLiveTest.java
index 7ab8c2a..e600072 100644
--- a/labs/fgcp/src/test/java/org/jclouds/http/internal/HttpInternalsLiveTest.java
+++ b/labs/fgcp/src/test/java/org/jclouds/http/internal/HttpInternalsLiveTest.java
@@ -31,8 +31,8 @@
 @Test(groups = "live", enabled = true, singleThreaded = true, testName = "HttpInternalsLiveTest")
 public class HttpInternalsLiveTest extends BaseFGCPApiLiveTest {
 
-    @Test
-    public void testTrustedSSLContext() {
-    	assertNotNull(context.utils().injector().getInstance(JavaUrlHttpCommandExecutorService.class).sslContextSupplier);
-    }
+   @Test
+   public void testTrustedSSLContext() {
+   	assertNotNull(context.utils().injector().getInstance(JavaUrlHttpCommandExecutorService.class).sslContextSupplier);
+   }
 }
diff --git a/labs/glesys/pom.xml b/labs/glesys/pom.xml
deleted file mode 100644
index d732237..0000000
--- a/labs/glesys/pom.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-  Licensed to jclouds, Inc. (jclouds) under one or more
-  contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  jclouds licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <groupId>org.jclouds</groupId>
-    <artifactId>jclouds-project</artifactId>
-    <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../project/pom.xml</relativePath>
-  </parent>
-  <groupId>org.jclouds.labs</groupId>
-  <artifactId>glesys</artifactId>
-  <name>jclouds GleSYS core</name>
-  <description>jclouds components to access GleSYS</description>
-  <packaging>bundle</packaging>
-
-  <properties>
-    <test.glesys.endpoint>https://api.glesys.com</test.glesys.endpoint>
-    <test.glesys.api-version>1</test.glesys.api-version>
-    <test.glesys.build-version />
-    <test.glesys.identity>FIXME</test.glesys.identity>
-    <test.glesys.credential>FIXME</test.glesys.credential>
-    <test.glesys.template />
-    <jclouds.osgi.export>org.jclouds.glesys*;version="${project.version}"</jclouds.osgi.export>
-    <jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
-  </properties>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.jclouds</groupId>
-      <artifactId>jclouds-compute</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.jclouds</groupId>
-      <artifactId>jclouds-core</artifactId>
-      <version>${project.version}</version>
-      <type>test-jar</type>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.jclouds</groupId>
-      <artifactId>jclouds-compute</artifactId>
-      <version>${project.version}</version>
-      <type>test-jar</type>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.jclouds.driver</groupId>
-      <artifactId>jclouds-log4j</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.jclouds.driver</groupId>
-      <artifactId>jclouds-sshj</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-  <profiles>
-    <profile>
-      <id>live</id>
-      <build>
-        <plugins>
-          <plugin>
-            <groupId>org.apache.maven.plugins</groupId>
-            <artifactId>maven-surefire-plugin</artifactId>
-            <executions>
-              <execution>
-                <id>integration</id>
-                <phase>integration-test</phase>
-                <goals>
-                  <goal>test</goal>
-                </goals>
-                <configuration>
-                  <systemPropertyVariables>
-                    <test.glesys.endpoint>${test.glesys.endpoint}</test.glesys.endpoint>
-                    <test.glesys.api-version>${test.glesys.api-version}</test.glesys.api-version>
-                    <test.glesys.build-version>${test.glesys.build-version}</test.glesys.build-version>
-                    <test.glesys.identity>${test.glesys.identity}</test.glesys.identity>
-                    <test.glesys.credential>${test.glesys.credential}</test.glesys.credential>
-                    <test.glesys.template>${test.glesys.template}</test.glesys.template>
-                  </systemPropertyVariables>
-                </configuration>
-              </execution>
-            </executions>
-          </plugin>
-        </plugins>
-      </build>
-    </profile>
-  </profiles>
-
-</project>
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSApi.java
deleted file mode 100644
index 7852a01..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSApi.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys;
-
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.glesys.features.ArchiveApi;
-import org.jclouds.glesys.features.DomainApi;
-import org.jclouds.glesys.features.EmailApi;
-import org.jclouds.glesys.features.IpApi;
-import org.jclouds.glesys.features.ServerApi;
-import org.jclouds.rest.annotations.Delegate;
-
-/**
- * Provides synchronous access to GleSYS.
- * <p/>
- * 
- * @see GleSYSAsyncApi
- * @see <a href="https://customer.glesys.com/api.php" />
- * @author Adrian Cole
- */
-@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
-public interface GleSYSApi {
-
-   /**
-    * Provides synchronous access to Server features.
-    */
-   @Delegate
-   ServerApi getServerApi();
-
-   /**
-    * Provides synchronous access to Ip Address features.
-    */
-   @Delegate
-   IpApi getIpApi();
-
-   /**
-    * Provides synchronous access to Archive features.
-    */
-   @Delegate
-   ArchiveApi getArchiveApi();
-
-   /**
-    * Provides synchronous access to DNS features.
-    */
-   @Delegate
-   DomainApi getDomainApi();
-
-   /**
-    * Provides synchronous access to E-Mail features.
-    */
-   @Delegate
-   EmailApi getEmailApi();
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSApiMetadata.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSApiMetadata.java
deleted file mode 100644
index 6325afc..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSApiMetadata.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys;
-
-import java.net.URI;
-import java.util.Properties;
-
-import org.jclouds.apis.ApiMetadata;
-import org.jclouds.compute.ComputeServiceContext;
-import org.jclouds.glesys.compute.config.GleSYSComputeServiceContextModule;
-import org.jclouds.glesys.config.GleSYSRestClientModule;
-import org.jclouds.rest.RestContext;
-import org.jclouds.rest.internal.BaseRestApiMetadata;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.reflect.TypeToken;
-import com.google.inject.Module;
-
-/**
- * Implementation of {@link ApiMetadata} for  API
- * 
- * @author Adrian Cole
- */
-public class GleSYSApiMetadata extends BaseRestApiMetadata {
-   
-   /** The serialVersionUID */
-   private static final long serialVersionUID = 6725672099385580694L;
-
-   public static final TypeToken<RestContext<GleSYSApi, GleSYSAsyncApi>> CONTEXT_TOKEN = new TypeToken<RestContext<GleSYSApi, GleSYSAsyncApi>>() {
-      private static final long serialVersionUID = -5070937833892503232L;
-   };
-   
-   @Override
-   public Builder toBuilder() {
-      return new Builder().fromApiMetadata(this);
-   }
-
-   public GleSYSApiMetadata() {
-      this(new Builder());
-   }
-
-   protected GleSYSApiMetadata(Builder builder) {
-      super(builder);
-   }
-
-   public static Properties defaultProperties() {
-      Properties properties = BaseRestApiMetadata.defaultProperties();
-      properties.setProperty("jclouds.ssh.max-retries", "5");
-      properties.setProperty("jclouds.ssh.retry-auth", "true");
-      return properties;
-   }
-
-   public static class Builder
-         extends
-         BaseRestApiMetadata.Builder {
-
-      protected Builder() {
-         super(GleSYSApi.class, GleSYSAsyncApi.class);
-         id("glesys")
-         .name("GleSYS API")
-         .identityName("Username")
-         .credentialName("API Key")
-         .documentation(URI.create("https://customer.glesys.com/api.php"))
-         .version("1")
-         .defaultEndpoint("https://api.glesys.com")
-         .defaultProperties(GleSYSApiMetadata.defaultProperties())
-         .view(TypeToken.of(ComputeServiceContext.class))
-         .defaultModules(ImmutableSet.<Class<? extends Module>>of(GleSYSComputeServiceContextModule.class, GleSYSRestClientModule.class));
-      }
-
-      @Override
-      public GleSYSApiMetadata build() {
-         return new GleSYSApiMetadata(this);
-      }
-
-      @Override
-      public Builder fromApiMetadata(ApiMetadata in) {
-         super.fromApiMetadata(in);
-         return this;
-      }
-
-   }
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncApi.java
deleted file mode 100644
index 65cedb0..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncApi.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys;
-
-import org.jclouds.glesys.features.ArchiveAsyncApi;
-import org.jclouds.glesys.features.DomainAsyncApi;
-import org.jclouds.glesys.features.EmailAsyncApi;
-import org.jclouds.glesys.features.IpAsyncApi;
-import org.jclouds.glesys.features.ServerAsyncApi;
-import org.jclouds.rest.annotations.Delegate;
-
-/**
- * Provides asynchronous access to GleSYS via their REST API.
- * <p/>
- * 
- * @see GleSYSApi
- * @see <a href="https://customer.glesys.com/api.php" />
- * @author Adrian Cole
- */
-public interface GleSYSAsyncApi {
-
-   /**
-    * Provides asynchronous access to Server features.
-    */
-   @Delegate
-   ServerAsyncApi getServerApi();
-
-   /**
-    * Provides asynchronous access to Ip Address features.
-    */
-   @Delegate
-   IpAsyncApi getIpApi();
-
-   /**
-    * Provides asynchronous access to Archive features.
-    */
-   @Delegate
-   ArchiveAsyncApi getArchiveApi();
-
-   /**
-    * Provides asynchronous access to DNS features.
-    */
-   @Delegate
-   DomainAsyncApi getDomainApi();
-
-   /**
-    * Provides asynchronous access to E-Mail features.
-    */
-   @Delegate
-   EmailAsyncApi getEmailApi();
-   
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java b/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java
deleted file mode 100644
index 20eccae..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys;
-
-import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
-import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
-import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONE;
-import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONES;
-
-import java.net.URI;
-import java.util.Properties;
-
-import org.jclouds.providers.ProviderMetadata;
-import org.jclouds.providers.internal.BaseProviderMetadata;
-
-/**
- * Implementation of {@link org.jclouds.types.ProviderMetadata} for GleSYS.
- * @author Adrian Cole
- */
-public class GleSYSProviderMetadata extends BaseProviderMetadata {
-
-   /** The serialVersionUID */
-   private static final long serialVersionUID = 539076518401969165L;
-
-   public static Builder builder() {
-      return new Builder();
-   }
-
-   @Override
-   public Builder toBuilder() {
-      return builder().fromProviderMetadata(this);
-   }
-
-   public GleSYSProviderMetadata() {
-      super(builder());
-   }
-
-   public GleSYSProviderMetadata(Builder builder) {
-      super(builder);
-   }
-
-   public static Properties defaultProperties() {
-      Properties properties = new Properties();
-      properties.setProperty(PROPERTY_ZONES, "Amsterdam,Falkenberg,New York City,Stockholm");
-      properties.setProperty(PROPERTY_ZONE + ".Amsterdam." + ISO3166_CODES, "NL-NH");
-      properties.setProperty(PROPERTY_ZONE + ".Falkenberg." + ISO3166_CODES, "SE-N");
-      properties.setProperty(PROPERTY_ZONE + ".New York City." + ISO3166_CODES, "US-NY");
-      properties.setProperty(PROPERTY_ZONE + ".Stockholm." + ISO3166_CODES, "SE-AB");
-      properties.setProperty(TEMPLATE, "minRam=512,osFamily=UBUNTU,hypervisorMatches=OpenVZ,osVersionMatches=1[012].[01][04],os64Bit=true,locationId=Falkenberg");
-      return properties;
-   }
-
-   public static class Builder extends BaseProviderMetadata.Builder {
-
-      protected Builder() {
-         id("glesys")
-         .name("GleSYS")
-         .apiMetadata(new GleSYSApiMetadata())
-         .homepage(URI.create("http://www.glesys.com"))
-         .console(URI.create("https://customer.glesys.com/cloud.php"))
-         .iso3166Codes("NL-NH","SE-N","US-NY","SE-AB")
-         .endpoint("https://api.glesys.com")
-         .defaultProperties(GleSYSProviderMetadata.defaultProperties());
-      }
-
-      @Override
-      public GleSYSProviderMetadata build() {
-         return new GleSYSProviderMetadata(this);
-      }
-
-      @Override
-      public Builder fromProviderMetadata(ProviderMetadata in) {
-         super.fromProviderMetadata(in);
-         return this;
-      }
-
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
deleted file mode 100644
index 85622d3..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.compute;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.jclouds.concurrent.FutureIterables.transformParallel;
-
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-
-import javax.annotation.Resource;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.jclouds.Constants;
-import org.jclouds.collect.FindResourceInSet;
-import org.jclouds.collect.Memoized;
-import org.jclouds.compute.ComputeService;
-import org.jclouds.compute.ComputeServiceAdapter;
-import org.jclouds.compute.domain.Hardware;
-import org.jclouds.compute.domain.HardwareBuilder;
-import org.jclouds.compute.domain.Processor;
-import org.jclouds.compute.domain.Template;
-import org.jclouds.compute.domain.Volume;
-import org.jclouds.compute.domain.internal.VolumeImpl;
-import org.jclouds.compute.predicates.ImagePredicates;
-import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
-import org.jclouds.domain.Location;
-import org.jclouds.domain.LoginCredentials;
-import org.jclouds.glesys.GleSYSAsyncApi;
-import org.jclouds.glesys.GleSYSApi;
-import org.jclouds.glesys.compute.options.GleSYSTemplateOptions;
-import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
-import org.jclouds.glesys.domain.OSTemplate;
-import org.jclouds.glesys.domain.Server;
-import org.jclouds.glesys.domain.ServerDetails;
-import org.jclouds.glesys.domain.ServerSpec;
-import org.jclouds.glesys.options.CreateServerOptions;
-import org.jclouds.glesys.options.DestroyServerOptions;
-import org.jclouds.location.predicates.LocationPredicates;
-import org.jclouds.logging.Logger;
-import org.jclouds.predicates.RetryablePredicate;
-import org.jclouds.util.Iterables2;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-/**
- * defines the connection between the {@link GleSYSApi} implementation and
- * the jclouds {@link ComputeService}
- * 
- */
-@Singleton
-public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter<ServerDetails, Hardware, OSTemplate, String> {
-
-   @Resource
-   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-   protected Logger logger = Logger.NULL;
-
-   private final GleSYSApi api;
-   private final GleSYSAsyncApi aapi;
-   private final ExecutorService userThreads;
-   private final Timeouts timeouts;
-   private final Supplier<Set<? extends Location>> locations;
-   private final Provider<String> passwordProvider;
-
-   @Inject
-   public GleSYSComputeServiceAdapter(GleSYSApi api, GleSYSAsyncApi aapi,
-         @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, Timeouts timeouts,
-         @Memoized Supplier<Set<? extends Location>> locations, @Named("PASSWORD") Provider<String> passwordProvider) {
-      this.api = checkNotNull(api, "api");
-      this.aapi = checkNotNull(aapi, "aapi");
-      this.userThreads = checkNotNull(userThreads, "userThreads");
-      this.timeouts = checkNotNull(timeouts, "timeouts");
-      this.locations = checkNotNull(locations, "locations");
-      this.passwordProvider = checkNotNull(passwordProvider, "passwordProvider");
-   }
-
-   @Override
-   public NodeAndInitialCredentials<ServerDetails> createNodeWithGroupEncodedIntoName(String group, String name,
-         Template template) {
-      checkNotNull(template, "template was null");
-      checkNotNull(template.getOptions(), "template options was null");
-      checkArgument(template.getOptions().getClass().isAssignableFrom(GleSYSTemplateOptions.class),
-            "options class %s should have been assignable from GleSYSTemplateOptions", template.getOptions().getClass());
-
-      GleSYSTemplateOptions templateOptions = template.getOptions().as(GleSYSTemplateOptions.class);
-
-      CreateServerOptions createServerOptions = new CreateServerOptions();
-      createServerOptions.ip(templateOptions.getIp());
-
-      createServerOptions.description(name); // TODO: add to templateOptions and
-                                             // set if present
-
-      ServerSpec.Builder<?> builder = ServerSpec.builder();
-      builder.datacenter(template.getLocation().getId());
-      builder.templateName(template.getImage().getId());
-      builder.platform(template.getHardware().getHypervisor());
-      builder.memorySizeMB(template.getHardware().getRam());
-      builder.diskSizeGB(Math.round(template.getHardware().getVolumes().get(0).getSize()));
-      builder.cpuCores((int) template.getHardware().getProcessors().get(0).getCores());
-      builder.transferGB(50);// TODO: add to template options with default value
-      ServerSpec spec = builder.build();
-
-      String password = passwordProvider.get(); // TODO: add to templateOptions
-                                                // and set if present
-
-      logger.debug(">> creating new Server spec(%s) name(%s) options(%s)", spec, name, createServerOptions);
-      ServerDetails result = api.getServerApi().createServerWithHostnameAndRootPassword(spec, name, password,
-            createServerOptions);
-      logger.trace("<< server(%s)", result.getId());
-
-      return new NodeAndInitialCredentials<ServerDetails>(result, result.getId() + "", LoginCredentials.builder()
-            .password(password).build());
-   }
-
-   @Singleton
-   public static class FindLocationForServerSpec extends FindResourceInSet<ServerSpec, Location> {
-
-      @Inject
-      public FindLocationForServerSpec(@Memoized Supplier<Set<? extends Location>> location) {
-         super(location);
-      }
-
-      @Override
-      public boolean matches(ServerSpec from, Location input) {
-         return input.getId().equals(from.getDatacenter());
-      }
-   }
-
-   @Override
-   public Iterable<Hardware> listHardwareProfiles() {
-      Set<? extends Location> locationsSet = locations.get();
-      ImmutableSet.Builder<Hardware> hardwareToReturn = ImmutableSet.builder();
-
-      // do this loop after dupes are filtered, else OOM
-      Set<OSTemplate> images = listImages();
-
-      for (Entry<String, AllowedArgumentsForCreateServer> platformToArgs : api.getServerApi()
-            .getAllowedArgumentsForCreateServerByPlatform().entrySet())
-         for (String datacenter : platformToArgs.getValue().getDataCenters())
-            for (int diskSizeGB : platformToArgs.getValue().getDiskSizesInGB())
-               for (int cpuCores : platformToArgs.getValue().getCpuCoreOptions())
-                  for (int memorySizeMB : platformToArgs.getValue().getMemorySizesInMB()) {
-                     ImmutableSet.Builder<String> templatesSupportedBuilder = ImmutableSet.builder();
-                     for (OSTemplate template : images) {
-                        if (template.getPlatform().equals(platformToArgs.getKey())
-                              && diskSizeGB >= template.getMinDiskSize() && memorySizeMB >= template.getMinMemSize())
-                           templatesSupportedBuilder.add(template.getName());
-                     }
-                     ImmutableSet<String> templatesSupported = templatesSupportedBuilder.build();
-                     if (templatesSupported.size() > 0)
-                        hardwareToReturn.add(new HardwareBuilder()
-                              .ids(String.format(
-                                    "datacenter(%s)platform(%s)cpuCores(%d)memorySizeMB(%d)diskSizeGB(%d)", datacenter,
-                                    platformToArgs.getKey(), cpuCores, memorySizeMB, diskSizeGB)).ram(memorySizeMB)
-                              .processors(ImmutableList.of(new Processor(cpuCores, 1.0)))
-                              .volumes(ImmutableList.<Volume> of(new VolumeImpl((float) diskSizeGB, true, true)))
-                              .hypervisor(platformToArgs.getKey())
-                              .location(Iterables.find(locationsSet, LocationPredicates.idEquals(datacenter)))
-                              .supportsImage(ImagePredicates.idIn(templatesSupported)).build());
-                  }
-
-      return hardwareToReturn.build();
-   }
-
-   @Override
-   public Set<OSTemplate> listImages() {
-      return api.getServerApi().listTemplates();
-   }
-   
-   // cheat until we have a getTemplate command
-   @Override
-   public OSTemplate getImage(final String id) {
-      return Iterables.find(listImages(), new Predicate<OSTemplate>(){
-
-         @Override
-         public boolean apply(OSTemplate input) {
-            return input.getName().equals(id);
-         }
-         
-      }, null);
-   }
-   
-   @Override
-   public Iterable<ServerDetails> listNodes() {
-      return Iterables2.concreteCopy(transformParallel(api.getServerApi().listServers(), new Function<Server, Future<? extends ServerDetails>>() {
-         @Override
-         public Future<ServerDetails> apply(Server from) {
-            return aapi.getServerApi().getServerDetails(from.getId());
-         }
-
-      }, userThreads, null, logger, "server details"));
-   }
-
-   @Override
-   public Set<String> listLocations() {
-      return ImmutableSet.copyOf(Iterables.concat(Iterables.transform(api.getServerApi()
-            .getAllowedArgumentsForCreateServerByPlatform().values(),
-            new Function<AllowedArgumentsForCreateServer, Set<String>>() {
-
-               @Override
-               public Set<String> apply(AllowedArgumentsForCreateServer arg0) {
-                  return arg0.getDataCenters();
-               }
-
-            })));
-   }
-
-   @Override
-   public ServerDetails getNode(String id) {
-      return api.getServerApi().getServerDetails(id);
-   }
-
-   @Override
-   public void destroyNode(String id) {
-      new RetryablePredicate<String>(new Predicate<String>() {
-
-         @Override
-         public boolean apply(String arg0) {
-            try {
-               api.getServerApi().destroyServer(arg0, DestroyServerOptions.Builder.discardIp());
-               return true;
-            } catch (IllegalStateException e) {
-               return false;
-            }
-         }
-
-      }, timeouts.nodeTerminated).apply(id);
-   }
-
-   @Override
-   public void rebootNode(String id) {
-      api.getServerApi().rebootServer(id);
-   }
-
-   @Override
-   public void resumeNode(String id) {
-      api.getServerApi().startServer(id);
-   }
-
-   @Override
-   public void suspendNode(String id) {
-      api.getServerApi().stopServer(id);
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java
deleted file mode 100644
index f9624c1..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.compute.functions;
-
-import static com.google.common.base.Predicates.containsPattern;
-
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import org.jclouds.compute.domain.OsFamily;
-import org.jclouds.compute.domain.OsFamilyVersion64Bit;
-import org.jclouds.compute.util.ComputeServiceUtils;
-
-import com.google.common.base.Function;
-
-/**
- * Defaults to version null and 64bit, if the operating system is unrecognized
- * and the pattern "32bit" isn't in the string.
- * 
- * @author Adrian Cole
- * 
- */
-@Singleton
-public class ParseOsFamilyVersion64BitFromImageName implements Function<String, OsFamilyVersion64Bit> {
-   private final Map<OsFamily, Map<String, String>> osVersionMap;
-
-   @Inject
-   public ParseOsFamilyVersion64BitFromImageName(Map<OsFamily, Map<String, String>> osVersionMap) {
-      this.osVersionMap = osVersionMap;
-   }
-
-   // ex Debian 6.0 64-bit
-   // ex. Ubuntu 10.04 LTS 32-bit
-   public static final Pattern OSFAMILY_VERSION = Pattern
-         .compile("([^ ]+).*[ -]([0-9.]+)( LTS)?( [36][24]-bit)?( x[68][46])?$");
-   public static final Pattern OSFAMILY = Pattern.compile("([^ ]+).*$");
-
-   @Override
-   public OsFamilyVersion64Bit apply(String input) {
-      boolean is64Bit = containsPattern("64").apply(input);
-      String version = "";
-
-      if (input.indexOf("Windows") != -1) {
-         Matcher matcher = Pattern.compile(".*(20[01][0-9] R[1-9]).*").matcher(input);
-         if (matcher.find()) {
-            version = matcher.group(1);
-         } else {
-            matcher = Pattern.compile(".*(20[01][0-9]).*").matcher(input);
-            if (matcher.find())
-               version = matcher.group(1);
-         }
-         return new OsFamilyVersion64Bit(OsFamily.WINDOWS, osVersionMap.get(OsFamily.WINDOWS).get(version), is64Bit);
-      }
-      Matcher osFamilyVersionMatcher = OSFAMILY_VERSION.matcher(input);
-      if (osFamilyVersionMatcher.find()) {
-         OsFamily fam = OsFamily.fromValue(osFamilyVersionMatcher.group(1).toLowerCase());
-         switch (fam) {
-         case UNRECOGNIZED:
-            return new OsFamilyVersion64Bit(OsFamily.UNRECOGNIZED, version, is64Bit);
-         }
-         return new OsFamilyVersion64Bit(fam, ComputeServiceUtils.parseVersionOrReturnEmptyString(fam,
-               osFamilyVersionMatcher.group(2), osVersionMap), is64Bit);
-      } else {
-         Matcher osFamilyMatcher = OSFAMILY.matcher(input);
-         OsFamily fam = OsFamily.UNRECOGNIZED;
-         if (osFamilyMatcher.find()) {
-            fam = OsFamily.fromValue(osFamilyMatcher.group(1).toLowerCase());
-         }
-         return new OsFamilyVersion64Bit(fam, version, is64Bit);
-      }
-
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java
deleted file mode 100644
index 4748c68..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.compute.functions;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-import javax.annotation.Resource;
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.jclouds.collect.FindResourceInSet;
-import org.jclouds.collect.Memoized;
-import org.jclouds.compute.domain.HardwareBuilder;
-import org.jclouds.compute.domain.Image;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.NodeMetadata.Status;
-import org.jclouds.compute.domain.NodeMetadataBuilder;
-import org.jclouds.compute.domain.OperatingSystem;
-import org.jclouds.compute.domain.Processor;
-import org.jclouds.compute.domain.Volume;
-import org.jclouds.compute.domain.internal.VolumeImpl;
-import org.jclouds.compute.functions.GroupNamingConvention;
-import org.jclouds.compute.reference.ComputeServiceConstants;
-import org.jclouds.domain.Location;
-import org.jclouds.glesys.domain.Ip;
-import org.jclouds.glesys.domain.ServerDetails;
-import org.jclouds.logging.Logger;
-import org.jclouds.util.InetAddresses2.IsPrivateIPAddress;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.base.Strings;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-
-/**
- * @author Adrian Cole
- */
-@Singleton
-public class ServerDetailsToNodeMetadata implements Function<ServerDetails, NodeMetadata> {
-   @Resource
-   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-   protected Logger logger = Logger.NULL;
-   public static final Map<ServerDetails.State, Status> serverStateToNodeStatus = ImmutableMap
-         .<ServerDetails.State, Status> builder().put(ServerDetails.State.STOPPED, Status.SUSPENDED)
-         .put(ServerDetails.State.LOCKED, Status.PENDING)
-         .put(ServerDetails.State.RUNNING, Status.RUNNING)
-         .put(ServerDetails.State.UNRECOGNIZED, Status.UNRECOGNIZED).build();
-
-   protected final Supplier<Set<? extends Image>> images;
-   protected final FindLocationForServerDetails findLocationForServerDetails;
-   protected final GroupNamingConvention nodeNamingConvention;
-
-   private static class FindImageForServer implements Predicate<Image> {
-      private final ServerDetails instance;
-
-      private FindImageForServer(ServerDetails instance) {
-         this.instance = instance;
-      }
-
-      @Override
-      public boolean apply(Image input) {
-         return input.getProviderId().equals(instance.getTemplateName());
-      }
-   }
-
-   @Inject
-   ServerDetailsToNodeMetadata(FindLocationForServerDetails findLocationForServerDetails,
-         @Memoized Supplier<Set<? extends Image>> images,
-         GroupNamingConvention.Factory namingConvention) {
-      this.nodeNamingConvention = checkNotNull(namingConvention, "namingConvention").createWithoutPrefix();
-      this.findLocationForServerDetails = checkNotNull(findLocationForServerDetails, "findLocationForServerDetails");
-      this.images = checkNotNull(images, "images");
-   }
-
-   @Override
-   public NodeMetadata apply(ServerDetails from) {
-      NodeMetadataBuilder builder = new NodeMetadataBuilder();
-      builder.ids(from.getId() + "");
-      builder.name(from.getHostname());
-      builder.hostname(from.getHostname());
-      Location location = findLocationForServerDetails.apply(from);
-      assert (location != null) : String.format("no location matched ServerDetails %s", from);
-      builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getDescription()));
-      builder.imageId(from.getTemplateName() + "");
-      builder.operatingSystem(parseOperatingSystem(from));
-      builder.hardware(new HardwareBuilder().ids(from.getId() + "").ram(from.getMemorySizeMB())
-            .processors(ImmutableList.of(new Processor(from.getCpuCores(), 1.0)))
-            .volumes(ImmutableList.<Volume> of(new VolumeImpl((float) from.getDiskSizeGB(), true, true)))
-            .hypervisor(from.getPlatform()).build());
-      builder.status(serverStateToNodeStatus.get(from.getState()));
-      Iterable<String> addresses = Iterables.filter(Iterables.transform(from.getIps(), new Function<Ip, String>() {
-
-         @Override
-         public String apply(Ip arg0) {
-            return Strings.emptyToNull(arg0.getIp());
-         }
-
-      }), Predicates.notNull());
-      builder.publicAddresses(Iterables.filter(addresses, Predicates.not(IsPrivateIPAddress.INSTANCE)));
-      builder.privateAddresses(Iterables.filter(addresses, IsPrivateIPAddress.INSTANCE));
-      return builder.build();
-   }
-
-   protected OperatingSystem parseOperatingSystem(ServerDetails from) {
-      try {
-         return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem();
-      } catch (NoSuchElementException e) {
-         logger.debug("could not find a matching image for server %s", from);
-      }
-      return null;
-   }
-
-   @Singleton
-   public static class FindLocationForServerDetails extends FindResourceInSet<ServerDetails, Location> {
-
-      @Inject
-      public FindLocationForServerDetails(@Memoized Supplier<Set<? extends Location>> location) {
-         super(location);
-      }
-
-      @Override
-      public boolean matches(ServerDetails from, Location input) {
-         return input.getId().equals(from.getDatacenter());
-      }
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java
deleted file mode 100644
index 0a1a44b..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.compute.options;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.util.Map;
-
-import org.jclouds.compute.ComputeService;
-import org.jclouds.compute.options.TemplateOptions;
-import org.jclouds.glesys.features.ServerApi;
-
-import com.google.common.net.InetAddresses;
-
-/**
- * Contains options supported by the
- * {@link ComputeService#createNodesInGroup(String, int, TemplateOptions)} and
- * {@link ComputeService#createNodesInGroup(String, int, TemplateOptions)} operations on the
- * <em>glesys</em> provider.
- * 
- * <h2>Usage</h2> The recommended way to instantiate a {@link GleSYSTemplateOptions} object is to
- * statically import {@code GleSYSTemplateOptions.*} and invoke a static creation method followed by
- * an instance mutator (if needed):
- * <p>
- * 
- * <pre>
- * import static org.jclouds.compute.options.GleSYSTemplateOptions.Builder.*;
- * ComputeService api = // get connection
- * templateBuilder.options(inboundPorts(22, 80, 8080, 443));
- * Set&lt;? extends NodeMetadata&gt; set = api.createNodesInGroup(tag, 2, templateBuilder.build());
- * </pre>
- * 
- * @author Adrian Cole
- */
-public class GleSYSTemplateOptions extends TemplateOptions implements Cloneable {
-
-   protected String ip = "any";
-
-   @Override
-   public GleSYSTemplateOptions clone() {
-      GleSYSTemplateOptions options = new GleSYSTemplateOptions();
-      copyTo(options);
-      return options;
-   }
-
-   @Override
-   public void copyTo(TemplateOptions to) {
-      super.copyTo(to);
-      if (to instanceof GleSYSTemplateOptions) {
-         GleSYSTemplateOptions eTo = GleSYSTemplateOptions.class.cast(to);
-         eTo.ip(ip);
-      }
-   }
-
-   /**
-    * 
-    * @see ServerApi#createServerWithHostnameAndRootPassword
-    * @see InetAddresses#isInetAddress
-    */
-   public TemplateOptions ip(String ip) {
-      if (ip != null)
-         checkArgument("any".equals(ip) || InetAddresses.isInetAddress(ip), "ip %s is not valid", ip);
-      this.ip = ip;
-      return this;
-   }
-
-   public String getIp() {
-      return ip;
-   }
-
-   public static final GleSYSTemplateOptions NONE = new GleSYSTemplateOptions();
-
-   public static class Builder {
-
-      /**
-       * @see #ip
-       */
-      public static GleSYSTemplateOptions ip(String ip) {
-         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
-         return GleSYSTemplateOptions.class.cast(options.ip(ip));
-      }
-
-      // methods that only facilitate returning the correct object type
-
-      /**
-       * @see TemplateOptions#inboundPorts(int...)
-       */
-      public static GleSYSTemplateOptions inboundPorts(int... ports) {
-         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
-         return GleSYSTemplateOptions.class.cast(options.inboundPorts(ports));
-      }
-
-      /**
-       * @see TemplateOptions#blockOnPort(int, int)
-       */
-      public static GleSYSTemplateOptions blockOnPort(int port, int seconds) {
-         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
-         return GleSYSTemplateOptions.class.cast(options.blockOnPort(port, seconds));
-      }
-      
-      /**
-       * @see TemplateOptions#userMetadata(Map)
-       */
-      public static GleSYSTemplateOptions userMetadata(Map<String, String> userMetadata) {
-         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
-         return GleSYSTemplateOptions.class.cast(options.userMetadata(userMetadata));
-      }
-
-      /**
-       * @see TemplateOptions#userMetadata(String, String)
-       */
-      public static GleSYSTemplateOptions userMetadata(String key, String value) {
-         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
-         return GleSYSTemplateOptions.class.cast(options.userMetadata(key, value));
-      }
-   }
-
-   // methods that only facilitate returning the correct object type
-
-   /**
-    * @see TemplateOptions#blockOnPort(int, int)
-    */
-   @Override
-   public GleSYSTemplateOptions blockOnPort(int port, int seconds) {
-      return GleSYSTemplateOptions.class.cast(super.blockOnPort(port, seconds));
-   }
-
-   /**
-    * @see TemplateOptions#inboundPorts(int...)
-    */
-   @Override
-   public GleSYSTemplateOptions inboundPorts(int... ports) {
-      return GleSYSTemplateOptions.class.cast(super.inboundPorts(ports));
-   }
-
-   /**
-    * @see TemplateOptions#authorizePublicKey(String)
-    */
-   @Override
-   public GleSYSTemplateOptions authorizePublicKey(String publicKey) {
-      return GleSYSTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
-   }
-
-   /**
-    * @see TemplateOptions#installPrivateKey(String)
-    */
-   @Override
-   public GleSYSTemplateOptions installPrivateKey(String privateKey) {
-      return GleSYSTemplateOptions.class.cast(super.installPrivateKey(privateKey));
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public GleSYSTemplateOptions userMetadata(Map<String, String> userMetadata) {
-      return GleSYSTemplateOptions.class.cast(super.userMetadata(userMetadata));
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   @Override
-   public GleSYSTemplateOptions userMetadata(String key, String value) {
-      return GleSYSTemplateOptions.class.cast(super.userMetadata(key, value));
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java b/labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java
deleted file mode 100644
index 7c9f994..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.config;
-
-import java.util.Map;
-
-import org.jclouds.glesys.GleSYSAsyncApi;
-import org.jclouds.glesys.GleSYSApi;
-import org.jclouds.glesys.features.ArchiveAsyncApi;
-import org.jclouds.glesys.features.ArchiveApi;
-import org.jclouds.glesys.features.DomainAsyncApi;
-import org.jclouds.glesys.features.DomainApi;
-import org.jclouds.glesys.features.EmailAsyncApi;
-import org.jclouds.glesys.features.EmailApi;
-import org.jclouds.glesys.features.IpAsyncApi;
-import org.jclouds.glesys.features.IpApi;
-import org.jclouds.glesys.features.ServerAsyncApi;
-import org.jclouds.glesys.features.ServerApi;
-import org.jclouds.glesys.handlers.GleSYSErrorHandler;
-import org.jclouds.http.HttpErrorHandler;
-import org.jclouds.http.HttpRetryHandler;
-import org.jclouds.http.annotation.ClientError;
-import org.jclouds.http.annotation.Redirection;
-import org.jclouds.http.annotation.ServerError;
-import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
-import org.jclouds.location.suppliers.ImplicitLocationSupplier;
-import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstZone;
-import org.jclouds.rest.ConfiguresRestClient;
-import org.jclouds.rest.config.RestClientModule;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.inject.Scopes;
-
-/**
- * Configures the GleSYS connection.
- * 
- * @author Adrian Cole
- */
-@ConfiguresRestClient
-public class GleSYSRestClientModule extends RestClientModule<GleSYSApi, GleSYSAsyncApi> {
-
-   public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
-         .put(ServerApi.class, ServerAsyncApi.class)//
-         .put(IpApi.class, IpAsyncApi.class)//
-         .put(ArchiveApi.class, ArchiveAsyncApi.class)//
-         .put(DomainApi.class, DomainAsyncApi.class)//
-         .put(EmailApi.class, EmailAsyncApi.class)//
-         .build();
-
-   public GleSYSRestClientModule() {
-      super(DELEGATE_MAP);
-   }
-
-   @Override
-   protected void configure() {
-      install(new GleSYSParserModule());
-      super.configure();
-   }
-
-   @Override
-   protected void bindErrorHandlers() {
-      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(GleSYSErrorHandler.class);
-      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(GleSYSErrorHandler.class);
-      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(GleSYSErrorHandler.class);
-   }
-
-   @Override
-   protected void bindRetryHandlers() {
-      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);
-   }
-   
-   @Override
-   protected void installLocations() {
-      super.installLocations();
-      bind(ImplicitLocationSupplier.class).to(OnlyLocationOrFirstZone.class).in(Scopes.SINGLETON);
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java
deleted file mode 100644
index 5d3621c..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.domain;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.beans.ConstructorProperties;
-import java.util.List;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-import com.google.common.collect.ImmutableList;
-
-/**
- * The allowed arguments for archive manipulation, such as archivesize
- *
- * @author Adam Lowe
- * @see <a href= "https://customer.glesys.com/api.php?a=doc#archive_allowedarguments" />
- */
-public class ArchiveAllowedArguments {
-
-   public static Builder<?> builder() {
-      return new ConcreteBuilder();
-   }
-
-   public Builder<?> toBuilder() {
-      return new ConcreteBuilder().fromArchiveAllowedArguments(this);
-   }
-
-   public static abstract class Builder<T extends Builder<T>> {
-      protected abstract T self();
-
-      protected List<Integer> archiveSizes = ImmutableList.of();
-
-      /**
-       * @see ArchiveAllowedArguments#getArchiveSizes()
-       */
-      public T archiveSizes(List<Integer> archiveSizes) {
-         this.archiveSizes = ImmutableList.copyOf(checkNotNull(archiveSizes, "archiveSizes"));
-         return self();
-      }
-
-      public T archiveSizes(Integer... in) {
-         return archiveSizes(ImmutableList.copyOf(in));
-      }
-
-      public ArchiveAllowedArguments build() {
-         return new ArchiveAllowedArguments(archiveSizes);
-      }
-
-      public T fromArchiveAllowedArguments(ArchiveAllowedArguments in) {
-         return this.archiveSizes(in.getArchiveSizes());
-      }
-   }
-
-   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-      @Override
-      protected ConcreteBuilder self() {
-         return this;
-      }
-   }
-
-   private final List<Integer> archiveSizes;
-
-   @ConstructorProperties({
-         "archivesize"
-   })
-   protected ArchiveAllowedArguments(List<Integer> archiveSizes) {
-      this.archiveSizes = ImmutableList.copyOf(checkNotNull(archiveSizes, "archiveSizes"));
-   }
-
-   /**
-    * @return the list of allowed archive sizes, in GB
-    */
-   public List<Integer> getArchiveSizes() {
-      return this.archiveSizes;
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(archiveSizes);
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null || getClass() != obj.getClass()) return false;
-      ArchiveAllowedArguments that = ArchiveAllowedArguments.class.cast(obj);
-      return Objects.equal(this.archiveSizes, that.archiveSizes);
-   }
-
-   protected ToStringHelper string() {
-      return Objects.toStringHelper("")
-            .add("archiveSizes", archiveSizes);
-   }
-
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java
deleted file mode 100644
index 30b34b4..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.domain;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.beans.ConstructorProperties;
-import java.util.Date;
-
-import org.jclouds.javax.annotation.Nullable;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * Domain data for a Glesys account.
- *
- * @author Adam Lowe
- * @see <a href= "https://customer.glesys.com/api.php?a=doc#domain_list" />
- */
-public class Domain {
-
-   public static Builder<?> builder() {
-      return new ConcreteBuilder();
-   }
-
-   public Builder<?> toBuilder() {
-      return new ConcreteBuilder().fromDomain(this);
-   }
-
-   public static abstract class Builder<T extends Builder<T>> {
-      protected abstract T self();
-
-      protected String domainName;
-      protected Date createTime;
-      protected int recordCount;
-      protected boolean useGlesysNameServer;
-      protected String primaryNameServer;
-      protected String responsiblePerson;
-      protected int ttl;
-      protected int refresh;
-      protected int retry;
-      protected int expire;
-      protected int minimum;
-
-      /**
-       * @see Domain#getDomainName()
-       */
-      public T domainName(String domainName) {
-         this.domainName = checkNotNull(domainName, "domainName");
-         return self();
-      }
-
-      /**
-       * @see Domain#getCreateTime()
-       */
-      public T createTime(Date createTime) {
-         this.createTime = createTime;
-         return self();
-      }
-
-      /**
-       * @see Domain#getRecordCount()
-       */
-      public T recordCount(int recordCount) {
-         this.recordCount = recordCount;
-         return self();
-      }
-
-      /**
-       * @see Domain#isUseGlesysNameServer()
-       */
-      public T useGlesysNameServer(boolean useGlesysNameServer) {
-         this.useGlesysNameServer = useGlesysNameServer;
-         return self();
-      }
-
-      /**
-       * @see Domain#getPrimaryNameServer()
-       */
-      public T primaryNameServer(String primaryNameServer) {
-         this.primaryNameServer = primaryNameServer;
-         return self();
-      }
-
-      /**
-       * @see Domain#getResponsiblePerson()
-       */
-      public T responsiblePerson(String responsiblePerson) {
-         this.responsiblePerson = responsiblePerson;
-         return self();
-      }
-
-      /**
-       * @see Domain#getTtl()
-       */
-      public T ttl(int ttl) {
-         this.ttl = ttl;
-         return self();
-      }
-
-      /**
-       * @see Domain#getRefresh()
-       */
-      public T refresh(int refresh) {
-         this.refresh = refresh;
-         return self();
-      }
-
-      /**
-       * @see Domain#getRetry()
-       */
-      public T retry(int retry) {
-         this.retry = retry;
-         return self();
-      }
-
-      /**
-       * @see Domain#getExpire()
-       */
-      public T expire(int expire) {
-         this.expire = expire;
-         return self();
-      }
-
-      /**
-       * @see Domain#getMinimum()
-       */
-      public T minimum(int minimum) {
-         this.minimum = minimum;
-         return self();
-      }
-
-      public Domain build() {
-         return new Domain(domainName, createTime, recordCount, new GleSYSBoolean(useGlesysNameServer), primaryNameServer, responsiblePerson, ttl, refresh, retry, expire, minimum);
-      }
-
-      public T fromDomain(Domain in) {
-         return this.domainName(in.getDomainName())
-               .createTime(in.getCreateTime())
-               .recordCount(in.getRecordCount())
-               .useGlesysNameServer(in.isUseGlesysNameServer())
-               .primaryNameServer(in.getPrimaryNameServer())
-               .responsiblePerson(in.getResponsiblePerson())
-               .ttl(in.getTtl())
-               .refresh(in.getRefresh())
-               .retry(in.getRetry())
-               .expire(in.getExpire());
-      }
-   }
-
-   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-      @Override
-      protected ConcreteBuilder self() {
-         return this;
-      }
-   }
-
-   private final String domainName;
-   private final Date createTime;
-   private final int recordCount;
-   private final boolean useGlesysNameServer;
-   private final String primaryNameServer;
-   private final String responsiblePerson;
-   private final int ttl;
-   private final int refresh;
-   private final int retry;
-   private final int expire;
-   private final int minimum;
-
-   @ConstructorProperties({
-         "domainname", "createtime", "recordcount", "usingglesysnameserver", "primarynameserver", "responsibleperson",
-         "ttl", "refresh", "retry", "expire", "minimum"
-   })
-   protected Domain(String domainName, @Nullable Date createTime, int recordCount, GleSYSBoolean useGlesysNameServer,
-                    @Nullable String primaryNameServer, @Nullable String responsiblePerson,
-                    int ttl, int refresh, int retry, int expire, int minimum) {
-      this.domainName = checkNotNull(domainName, "domainName");
-      this.createTime = createTime;
-      this.recordCount = recordCount;
-      this.useGlesysNameServer = checkNotNull(useGlesysNameServer, "useGlesysNameServer").getValue();
-      this.primaryNameServer = primaryNameServer;
-      this.responsiblePerson = responsiblePerson;
-      this.ttl = ttl;
-      this.refresh = refresh;
-      this.retry = retry;
-      this.expire = expire;
-      this.minimum = minimum;
-   }
-
-   /**
-    * @return the domain name, ex. "jclouds.org"
-    */
-   public String getDomainName() {
-      return this.domainName;
-   }
-
-   /**
-    * @return the date the domain was registered with GleSYS
-    */
-   public Date getCreateTime() {
-      return this.createTime;
-   }
-
-   /**
-    * @return the number of DNS records for this domain
-    */
-   public int getRecordCount() {
-      return this.recordCount;
-   }
-
-   /**
-    * @return true if a GleSYS nameserver holds the records
-    */
-   public boolean isUseGlesysNameServer() {
-      return this.useGlesysNameServer;
-   }
-
-   @Nullable
-   public String getPrimaryNameServer() {
-      return primaryNameServer;
-   }
-
-   /**
-    * The E-mail address of the person responsible for this domain (reformatted with '.' at end).
-    */
-   @Nullable
-   public String getResponsiblePerson() {
-      return responsiblePerson;
-   }
-
-   /**
-    * TTL (time to live). The number of seconds a domain name is cached locally before expiration and return to authoritative nameServers for updates
-    */
-   public int getTtl() {
-      return ttl;
-   }
-
-   /**
-    * The number of seconds between update requests from secondary and slave name servers
-    */
-   public int getRefresh() {
-      return refresh;
-   }
-
-
-   /**
-    * The number of seconds the secondary/slave will wait before retrying when the last attempt failed
-    */
-   public int getRetry() {
-      return retry;
-   }
-
-   /**
-    * The number of seconds a master or slave will wait before considering the data stale if it cannot reach the primary name server
-    */
-   public int getExpire() {
-      return expire;
-   }
-
-   /**
-    * The minimum/default TTL if the domain does not specify ttl
-    *
-    * @see #getTtl()
-    */
-   public int getMinimum() {
-      return minimum;
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(domainName);
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null || getClass() != obj.getClass()) return false;
-      Domain that = Domain.class.cast(obj);
-      return Objects.equal(this.domainName, that.domainName);
-   }
-
-   protected ToStringHelper string() {
-      return Objects.toStringHelper("")
-            .add("domainName", domainName).add("createTime", createTime).add("recordCount", recordCount).add("useGlesysNameServer", useGlesysNameServer);
-   }
-
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java
deleted file mode 100644
index 7ece758..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.domain;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.beans.ConstructorProperties;
-
-import org.jclouds.javax.annotation.Nullable;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * DNS record data.
- *
- * @author Adam Lowe
- * @see <a href= "https://customer.glesys.com/api.php?a=doc#domain_list_records" />
- */
-public class DomainRecord {
-
-   public static Builder<?> builder() {
-      return new ConcreteBuilder();
-   }
-
-   public Builder<?> toBuilder() {
-      return new ConcreteBuilder().fromDomainRecord(this);
-   }
-
-   public static abstract class Builder<T extends Builder<T>> {
-      protected abstract T self();
-
-      protected String id;
-      protected String domainname;
-      protected String host;
-      protected String type;
-      protected String data;
-      protected int ttl;
-
-      /**
-       * @see DomainRecord#getId()
-       */
-      public T id(String id) {
-         this.id = checkNotNull(id, "id");
-         return self();
-      }
-
-      /**
-       * @see DomainRecord#getDomainname()
-       */
-      public T domainname(String domainname) {
-         this.domainname = checkNotNull(domainname, "domainname");
-         return self();
-      }
-
-      /**
-       * @see DomainRecord#getHost()
-       */
-      public T host(String host) {
-         this.host = checkNotNull(host, "host");
-         return self();
-      }
-
-      /**
-       * @see DomainRecord#getType()
-       */
-      public T type(String type) {
-         this.type = checkNotNull(type, "type");
-         return self();
-      }
-
-      /**
-       * @see DomainRecord#getData()
-       */
-      public T data(String data) {
-         this.data = checkNotNull(data, "data");
-         return self();
-      }
-
-      /**
-       * @see DomainRecord#getTtl()
-       */
-      public T ttl(int ttl) {
-         this.ttl = ttl;
-         return self();
-      }
-
-      public DomainRecord build() {
-         return new DomainRecord(id, domainname, host, type, data, ttl);
-      }
-
-      public T fromDomainRecord(DomainRecord in) {
-         return this.id(in.getId())
-               .domainname(in.getDomainname())
-               .host(in.getHost())
-               .type(in.getType())
-               .data(in.getData())
-               .ttl(in.getTtl());
-      }
-   }
-
-   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-      @Override
-      protected ConcreteBuilder self() {
-         return this;
-      }
-   }
-
-   private final String id;
-   private final String domainname;
-   private final String host;
-   private final String type;
-   private final String data;
-   private final int ttl;
-
-   @ConstructorProperties({
-         "recordid", "domainname", "host", "type", "data", "ttl"
-   })
-   protected DomainRecord(@Nullable String id, String domainname, String host, String type, @Nullable String data, int ttl) {
-      this.id = id;
-      this.domainname = checkNotNull(domainname, "domainname");
-      this.host = checkNotNull(host, "host");
-      this.type = checkNotNull(type, "type");
-      this.data = data;
-      this.ttl = ttl;
-   }
-
-   /**
-    * @return the id of the record used to modify it via the API
-    * @see org.jclouds.glesys.features.DomainApi
-    */
-   public String getId() {
-      return this.id;
-   }
-
-   /**
-    * @return the zone content of the record
-    */
-   public String getDomainname() {
-      return this.domainname;
-   }
-
-   /**
-    * @return the host content of the record
-    */
-   public String getHost() {
-      return this.host;
-   }
-
-   /**
-    * @return the type of the record, ex. "A"
-    */
-   public String getType() {
-      return this.type;
-   }
-
-   /**
-    * @return the data content of the record
-    */
-   @Nullable
-   public String getData() {
-      return this.data;
-   }
-
-   /**
-    * @return the TTL/Time-to-live for the record
-    */
-   public int getTtl() {
-      return this.ttl;
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(id);
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null || getClass() != obj.getClass()) return false;
-      DomainRecord that = DomainRecord.class.cast(obj);
-      return Objects.equal(this.id, that.id);
-   }
-
-   protected ToStringHelper string() {
-      return Objects.toStringHelper("")
-            .add("id", id).add("domainname", domainname).add("host", host).add("type", type).add("data", data)
-            .add("ttl", ttl);
-   }
-
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java
deleted file mode 100644
index 88bdc4c..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.domain;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.beans.ConstructorProperties;
-import java.util.Set;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-import com.google.common.collect.ImmutableSet;
-
-/**
- * Structure containing all information about e-mail addresses for a GleSYS account
- *
- * @author Adam Lowe
- * @see <a href="https://customer.glesys.com/api.php?a=doc#email_overview" />
- */
-//TODO: find a better name for this class
-@Beta
-public class EmailOverview {
-
-   public static Builder<?> builder() {
-      return new ConcreteBuilder();
-   }
-
-   public Builder<?> toBuilder() {
-      return new ConcreteBuilder().fromEmailOverview(this);
-   }
-
-   public static abstract class Builder<T extends Builder<T>> {
-      protected abstract T self();
-
-      protected EmailOverviewSummary summary;
-      protected Set<EmailOverviewDomain> domains = ImmutableSet.of();
-
-      /**
-       * @see EmailOverview#getSummary()
-       */
-      public T summary(EmailOverviewSummary summary) {
-         this.summary = checkNotNull(summary, "summary");
-         return self();
-      }
-
-      /**
-       * @see EmailOverview#getDomains()
-       */
-      public T domains(Set<EmailOverviewDomain> domains) {
-         this.domains = ImmutableSet.copyOf(checkNotNull(domains, "domains"));
-         return self();
-      }
-
-      public T domains(EmailOverviewDomain... in) {
-         return domains(ImmutableSet.copyOf(in));
-      }
-
-      public EmailOverview build() {
-         return new EmailOverview(summary, domains);
-      }
-
-      public T fromEmailOverview(EmailOverview in) {
-         return this.summary(in.getSummary()).domains(in.getDomains());
-      }
-   }
-
-   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-      @Override
-      protected ConcreteBuilder self() {
-         return this;
-      }
-   }
-
-   private final EmailOverviewSummary summary;
-   private final Set<EmailOverviewDomain> domains;
-
-   @ConstructorProperties({
-         "summary", "domains"
-   })
-   protected EmailOverview(EmailOverviewSummary summary, Set<EmailOverviewDomain> domains) {
-      this.summary = checkNotNull(summary, "summary");
-      this.domains = ImmutableSet.copyOf(checkNotNull(domains, "domains"));
-   }
-
-   /**
-    * @return summary information about the account
-    */
-   public EmailOverviewSummary getSummary() {
-      return this.summary;
-   }
-
-   /**
-    * @return the set of detailed information about the e-mail addresses and aliases for each domain
-    */
-   public Set<EmailOverviewDomain> getDomains() {
-      return this.domains;
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(summary, domains);
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null || getClass() != obj.getClass()) return false;
-      EmailOverview that = EmailOverview.class.cast(obj);
-      return Objects.equal(this.summary, that.summary)
-            && Objects.equal(this.domains, that.domains);
-   }
-
-   protected ToStringHelper string() {
-      return Objects.toStringHelper("")
-            .add("summary", summary).add("domains", domains);
-   }
-
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java b/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java
deleted file mode 100644
index b201b2a..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.domain;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.beans.ConstructorProperties;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * Detailed information about e-mail settings for a single domain
- *
- * @author Adam Lowe
- * @see <a href="https://customer.glesys.com/api.php?a=doc#email_overview" />
- */
-@Beta
-public class EmailOverviewDomain {
-
-   public static Builder<?> builder() {
-      return new ConcreteBuilder();
-   }
-
-   public Builder<?> toBuilder() {
-      return new ConcreteBuilder().fromEmailOverviewDomain(this);
-   }
-
-   public static abstract class Builder<T extends Builder<T>> {
-      protected abstract T self();
-
-      protected String domain;
-      protected int accounts;
-      protected int aliases;
-
-      /**
-       * @see EmailOverviewDomain#getDomain()
-       */
-      public T domain(String domain) {
-         this.domain = checkNotNull(domain, "domain");
-         return self();
-      }
-
-      /**
-       * @see EmailOverviewDomain#getAccounts()
-       */
-      public T accounts(int accounts) {
-         this.accounts = accounts;
-         return self();
-      }
-
-      /**
-       * @see EmailOverviewDomain#getAliases()
-       */
-      public T aliases(int aliases) {
-         this.aliases = aliases;
-         return self();
-      }
-
-      public EmailOverviewDomain build() {
-         return new EmailOverviewDomain(domain, accounts, aliases);
-      }
-
-      public T fromEmailOverviewDomain(EmailOverviewDomain in) {
-         return this.domain(in.getDomain()).accounts(in.getAccounts()).aliases(in.getAliases());
-      }
-   }
-
-   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-      @Override
-      protected ConcreteBuilder self() {
-         return this;
-      }
-   }
-
-   private final String domain;
-   private final int accounts;
-   private final int aliases;
-
-   @ConstructorProperties({
-         "domainname", "accounts", "aliases"
-   })
-   protected EmailOverviewDomain(String domain, int accounts, int aliases) {
-      this.domain = checkNotNull(domain, "domain");
-      this.accounts = accounts;
-      this.aliases = aliases;
-   }
-
-   /** @return the domain name */
-   public String getDomain() {
-      return this.domain;
-   }
-
-   /** @return the number of e-mail accounts in the domain */
-   public int getAccounts() {
-      return this.accounts;
-   }
-
-   /** @return the number of e-mail aliases in the domain */
-   public int getAliases() {
-      return this.aliases;
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(domain);
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null || getClass() != obj.getClass()) return false;
-      EmailOverviewDomain that = EmailOverviewDomain.class.cast(obj);
-      return Objects.equal(this.domain, that.domain);
-   }
-
-   protected ToStringHelper string() {
-      return Objects.toStringHelper("").add("domain", domain).add("accounts", accounts).add("aliases", aliases);
-   }
-
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveApi.java
deleted file mode 100644
index d074a87..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveApi.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.glesys.domain.Archive;
-import org.jclouds.glesys.domain.ArchiveAllowedArguments;
-
-/**
- * Provides synchronous access to Archive requests.
- * <p/>
- *
- * @author Adam Lowe
- * @see ArchiveAsyncApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
-public interface ArchiveApi {
-
-   /**
-    * Lists all active disks on this account.
-    */
-   Set<Archive> listArchives();
-
-   /**
-    * Get detailed information about an archive volume.
-    *
-    * @param username the username associated with the archive
-    * @return the archive information or null if not found
-    */
-   Archive getArchive(String username);
-
-   /**
-    * Create a new backup volume.
-    *
-    * @param username the archive username, this must be prefixed by Glesys account name (in lower case) and an 
-    *                 underscore, ex. "c100005_archive1"
-    * @param password the new password
-    * @param size     the new size required in GB
-    */
-   Archive createArchive(String username, String password, int size);
-
-   /**
-    * Delete an archive volume. All files on the volume
-    *
-    * @param username the username associated with the archive
-    */
-   void deleteArchive(String username);
-
-   /**
-    * Resize an archive volume. It is only possible to upgrade the size of the disk. Downgrading is currently not
-    * supported. If you need to downgrade, please create a new volume and transfer all data to the new volume.
-    * Then delete the old volume.
-    *
-    * @param username the username associated with the archive
-    * @param size     the new size required, see #getArchiveAllowedArguments for valid values
-    */
-   Archive resizeArchive(String username, int size);
-
-   /**
-    * Change the password for an archive user.
-    *
-    * @param username the archive username
-    * @param password the new password
-    */
-   Archive changeArchivePassword(String username, String password);
-
-   /**
-    * Lists the allowed arguments for some of the functions in this module such as archive size.
-    */
-   ArchiveAllowedArguments getArchiveAllowedArguments();
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncApi.java
deleted file mode 100644
index 550c498..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncApi.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.Archive;
-import org.jclouds.glesys.domain.ArchiveAllowedArguments;
-import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.SelectJson;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides asynchronous access to Archive data via the Glesys REST API.
- * <p/>
- *
- * @author Adam Lowe
- * @see ArchiveApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@RequestFilters(BasicAuthentication.class)
-public interface ArchiveAsyncApi {
-
-   /**
-    * @see ArchiveApi#listArchives
-    */
-   @POST
-   @Path("/archive/list/format/json")
-   @SelectJson("archives")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<Set<Archive>> listArchives();
-
-   /**
-    * @see ArchiveApi#getArchive
-    */
-   @POST
-   @Path("/archive/details/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<Archive> getArchive(@FormParam("username") String username);
-
-   /**
-    * @see ArchiveApi#createArchive
-    */
-   @POST
-   @Path("/archive/create/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Archive> createArchive(@FormParam("username") String username, @FormParam("password") String password,
-                                        @FormParam("size")int size);
-
-   /**
-    * @see ArchiveApi#deleteArchive
-    */
-   @POST
-   @Path("/archive/delete/format/json")
-   ListenableFuture<Void> deleteArchive(@FormParam("username") String username);
-
-   /**
-    * @see ArchiveApi#resizeArchive
-    */
-   @POST
-   @Path("/archive/resize/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Archive> resizeArchive(@FormParam("username") String username, @FormParam("size") int size);
-   /**
-    * @see ArchiveApi#changeArchivePassword
-    */
-   @POST
-   @Path("/archive/changepassword/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Archive> changeArchivePassword(@FormParam("username") String username, @FormParam("password") String password);
-
-   /**
-    * @see org.jclouds.glesys.features.ArchiveApi#getArchiveAllowedArguments
-    */
-   @GET
-   @Path("/archive/allowedarguments/format/json")
-   @SelectJson("argumentslist")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<ArchiveAllowedArguments> getArchiveAllowedArguments();
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/DomainApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/DomainApi.java
deleted file mode 100644
index ca6a01d..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/DomainApi.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.glesys.domain.Domain;
-import org.jclouds.glesys.domain.DomainRecord;
-import org.jclouds.glesys.options.AddDomainOptions;
-import org.jclouds.glesys.options.AddRecordOptions;
-import org.jclouds.glesys.options.DomainOptions;
-import org.jclouds.glesys.options.EditRecordOptions;
-
-/**
- * Provides synchronous access to Domain requests.
- * <p/>
- *
- * @author Adam Lowe
- * @see DomainAsyncApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
-public interface DomainApi {
-
-   /**
-    * Get a list of all domains for this account.
-    *
-    * @return an account's associated domain objects.
-    */
-   Set<Domain> listDomains();
-
-   /**
-    * Get a specific domain.
-    *
-    * @return the requested domain object.
-    */
-   Domain getDomain(String domain);
-
-   /**
-    * Add a domain to the Glesys dns-system
-    *
-    * @param domain  the name of the domain to add.
-    * @param options optional parameters
-    * @return information about the added domain
-    */
-   Domain addDomain(String domain, AddDomainOptions... options);
-
-   /**
-    * Edit a domain to the Glesys dns-system
-    *
-    * @param domain  the name of the domain to add.
-    * @param options optional parameters
-    * @return information about the modified domain
-    */
-   Domain editDomain(String domain, DomainOptions... options);
-
-   /**
-    * Remove a domain to the Glesys dns-system
-    *
-    * @param domain the name of the domain to remove
-    */
-   void deleteDomain(String domain);
-
-   /**
-    * Retrieve the DNS records for a given domain
-    *
-    * @param domain the name of the domain to retrieve records for
-    */
-   Set<DomainRecord> listRecords(String domain);
-
-   /**
-    * Add a DNS Record
-    *
-    * @param domain  the domain to add the record to
-    * @param options optional settings for the record
-    */
-   DomainRecord addRecord(String domain, String host, String type, String data, AddRecordOptions... options);
-
-   /**
-    * Modify a specific DNS Record
-    *
-    * @param recordId the id for the record to edit
-    * @param options  the settings to change
-    * @see #listRecords to retrieve the necessary ids
-    */
-   DomainRecord editRecord(String recordId, EditRecordOptions... options);
-
-   /**
-    * Delete a DNS record
-    *
-    * @param recordId the id for the record to delete
-    * @see #listRecords to retrieve the necessary ids
-    */
-   void deleteRecord(String recordId);
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncApi.java
deleted file mode 100644
index 8fdbd19..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncApi.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.Domain;
-import org.jclouds.glesys.domain.DomainRecord;
-import org.jclouds.glesys.options.AddDomainOptions;
-import org.jclouds.glesys.options.AddRecordOptions;
-import org.jclouds.glesys.options.DomainOptions;
-import org.jclouds.glesys.options.EditRecordOptions;
-import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.SelectJson;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides asynchronous access to Domain (DNS) data via the Glesys REST API.
- * <p/>
- *
- * @author Adam Lowe
- * @see DomainApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@RequestFilters(BasicAuthentication.class)
-public interface DomainAsyncApi {
-
-   /**
-    * @see org.jclouds.glesys.features.DomainApi#listDomains
-    */
-   @POST
-   @Path("/domain/list/format/json")
-   @SelectJson("domains")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<Set<Domain>> listDomains();
-
-   /**
-    * @see org.jclouds.glesys.features.DomainApi#getDomain
-    */
-   @POST
-   @Path("/domain/details/format/json")
-   @SelectJson("domain")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<Domain> getDomain(@FormParam("domainname") String name);
-
-   /**
-    * @see DomainApi#addDomain
-    */
-   @POST
-   @Path("/domain/add/format/json")
-   @SelectJson("domain")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Domain> addDomain(@FormParam("domainname") String name, AddDomainOptions... options);
-
-   /**
-    * @see DomainApi#editDomain
-    */
-   @POST
-   @Path("/domain/edit/format/json")
-   @SelectJson("domain")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Domain> editDomain(@FormParam("domainname") String domain, DomainOptions... options);
-
-
-   /**
-    * @see DomainApi#deleteDomain
-    */
-   @POST
-   @Path("/domain/delete/format/json")
-   ListenableFuture<Void> deleteDomain(@FormParam("domainname") String domain);
-
-   /**
-    * @see DomainApi#listRecords
-    */
-   @POST
-   @Path("/domain/listrecords/format/json")
-   @SelectJson("records")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Set<DomainRecord>> listRecords(@FormParam("domainname") String domain);
-
-   /**
-    * @see DomainApi#addRecord
-    */
-   @POST
-   @Path("/domain/addrecord/format/json")
-   @SelectJson("record")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<DomainRecord> addRecord(@FormParam("domainname") String domain, @FormParam("host") String host,
-                                    @FormParam("type") String type, @FormParam("data") String data,
-                                    AddRecordOptions... options);
-
-   /**
-    * @see DomainApi#editRecord
-    */
-   @POST
-   @Path("/domain/updaterecord/format/json")
-   @SelectJson("record")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<DomainRecord> editRecord(@FormParam("recordid") String record_id, EditRecordOptions... options);
-
-   /**
-    * @see DomainApi#deleteRecord
-    */
-   @POST
-   @Path("/domain/deleterecord/format/json")
-   ListenableFuture<Void> deleteRecord(@FormParam("recordid") String recordId);
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/EmailApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/EmailApi.java
deleted file mode 100644
index e868043..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/EmailApi.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.glesys.domain.EmailAccount;
-import org.jclouds.glesys.domain.EmailAlias;
-import org.jclouds.glesys.domain.EmailOverview;
-import org.jclouds.glesys.options.CreateAccountOptions;
-import org.jclouds.glesys.options.EditAccountOptions;
-
-/**
- * Provides synchronous access to E-Mail requests.
- * <p/>
- *
- * @author Adam Lowe
- * @see org.jclouds.glesys.features.EmailAsyncApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
-public interface EmailApi {
-
-   /**
-    * Get a summary of e-mail accounts associated with this Glesys account
-    *
-    * @return the relevant summary data
-    */
-   EmailOverview getEmailOverview();
-
-   /**
-    * Get the set of detailed information about e-mail accounts
-    *
-    * @return the relevant set of details
-    */
-   Set<EmailAccount> listAccounts(String domain);
-
-   /**
-    * Get the set of details about e-mail aliases
-    *
-    * @return the relevant set of details
-    */
-   Set<EmailAlias> listAliases(String domain);
-
-   /**
-    * Create a new e-mail account
-    *
-    * @param accountAddress the e-mail address to use (the domain should already exist)
-    * @param password       the password to use for the mailbox
-    * @param options        optional parameters
-    * @see DomainApi#addDomain
-    */
-   EmailAccount createAccount(String accountAddress, String password, CreateAccountOptions... options);
-
-   /**
-    * Create an e-mail alias for an e-mail account
-    *
-    * @param aliasAddress   the address to use for the alias  (the domain should already exist)
-    * @param toEmailAddress the existing e-mail account address the alias should forward to
-    * @see DomainApi#addDomain
-    */
-   EmailAlias createAlias(String aliasAddress, String toEmailAddress);
-
-   /**
-    * Adjust an e-mail account's settings
-    *
-    * @param accountAddress the existing e-mail account address
-    * @param options        optional parameters
-    */
-   EmailAccount editAccount(String accountAddress, EditAccountOptions... options);
-
-   /**
-    * Adjust (re-target) an e-mail alias
-    *
-    * @param aliasAddress   the existing alias e-mail address
-    * @param toEmailAddress the existing e-mail account address the alias should forward to
-    */
-   EmailAlias editAlias(String aliasAddress, String toEmailAddress);
-
-   /**
-    * Delete an e-mail account or alias
-    *
-    * @param accountAddress the existing alias e-mail account or alias address
-    */
-   boolean delete(String accountAddress);
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncApi.java
deleted file mode 100644
index 2470729..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/EmailAsyncApi.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.EmailAccount;
-import org.jclouds.glesys.domain.EmailAlias;
-import org.jclouds.glesys.domain.EmailOverview;
-import org.jclouds.glesys.options.CreateAccountOptions;
-import org.jclouds.glesys.options.EditAccountOptions;
-import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.SelectJson;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides asynchronous access to E-Mail data via the Glesys REST API.
- * <p/>
- *
- * @author Adam Lowe
- * @see org.jclouds.glesys.features.EmailApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@RequestFilters(BasicAuthentication.class)
-public interface EmailAsyncApi {
-
-   /**
-    * @see org.jclouds.glesys.features.EmailApi#getEmailOverview
-    */
-   @POST
-   @Path("/email/overview/format/json")
-   @SelectJson("overview")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<EmailOverview> getEmailOverview();
-
-   /**
-    * @see org.jclouds.glesys.features.EmailApi#listAccounts
-    */
-   @POST
-   @Path("/email/list/format/json")
-   @SelectJson("emailaccounts")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<Set<EmailAccount>> listAccounts(@FormParam("domainname") String domain);
-
-   /**
-    * @see org.jclouds.glesys.features.EmailApi#listAccounts
-    */
-   @POST
-   @Path("/email/list/format/json")
-   @SelectJson("emailaliases")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<Set<EmailAlias>> listAliases(@FormParam("domainname") String domain);
-
-   /**
-    * @see org.jclouds.glesys.features.EmailApi#createAccount
-    */
-   @POST
-   @Consumes(MediaType.APPLICATION_JSON)
-   @SelectJson("emailaccount")
-   @Path("/email/createaccount/format/json")
-   ListenableFuture<EmailAccount> createAccount(@FormParam("emailaccount") String accountAddress, @FormParam("password") String password, CreateAccountOptions... options);
-
-   /**
-    * @see org.jclouds.glesys.features.EmailApi#createAlias
-    */
-   @POST
-   @Consumes(MediaType.APPLICATION_JSON)
-   @SelectJson("alias")
-   @Path("/email/createalias/format/json")
-   ListenableFuture<EmailAlias> createAlias(@FormParam("emailalias") String aliasAddress, @FormParam("goto") String toEmailAddress);
-
-   /**
-    * @see org.jclouds.glesys.features.EmailApi#editAccount
-    */
-   @POST
-   @Consumes(MediaType.APPLICATION_JSON)
-   @SelectJson("emailaccount")
-   @Path("/email/editaccount/format/json")
-   ListenableFuture<EmailAccount> editAccount(@FormParam("emailaccount") String accountAddress, EditAccountOptions... options);
-
-   /**
-    * @see org.jclouds.glesys.features.EmailApi#editAlias
-    */
-   @POST
-   @Consumes(MediaType.APPLICATION_JSON)
-   @SelectJson("alias")
-   @Path("/email/editalias/format/json")
-   ListenableFuture<EmailAlias> editAlias(@FormParam("emailalias") String aliasAddress, @FormParam("goto") String toEmailAddress);
-
-   /**
-    * @see org.jclouds.glesys.features.EmailApi#delete
-    */
-   @POST
-   @Path("/email/delete/format/json")
-   ListenableFuture<Boolean> delete(@FormParam("email") String accountAddress);
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/IpApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/IpApi.java
deleted file mode 100644
index b81ee87..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/IpApi.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.glesys.domain.IpDetails;
-import org.jclouds.glesys.options.ListIpOptions;
-
-/**
- * Provides synchronous access to IP Addresses.
- * <p/>
- *
- * @author Adrian Cole, Mattias Holmqvist, Adam Lowe
- * @see IpAsyncApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
-public interface IpApi {
-   /**
-    * Get a set of all IP addresses that are available and not used on any account or server.
-    *
-    * @param ipVersion  4 or 6, for IPV4 or IPV6, respectively
-    * @param datacenter the datacenter
-    * @param platform   the platform
-    * @return a set of free IP addresses
-    */
-   Set<String> listFree(int ipVersion, String datacenter, String platform);
-
-   /**
-    * Take a free IP address and add it to this account. You can list free IP addresses with the function listFree().
-    * Once your free IP on this account you can add it to a server with the add() function.
-    *
-    * @param ipAddress the IP address to be add to this account (reserve)
-    */
-   IpDetails take(String ipAddress);
-
-   /**
-    * Return an unused IP address to the pool of free ips. If the IP address is allocated to a server,
-    * it must first be removed by calling remove(ipAddress) before it can be released.
-    *
-    * @param ipAddress the IP address to be released
-    */
-   IpDetails release(String ipAddress);
-
-   /**
-    * Get IP addresses associated with your account (reserved, assigned to servers, etc)
-    *
-    * @param options options to filter the results (by IPV4/6, serverId, etc)
-    * @return the set of IP addresses
-    */
-   Set<IpDetails> listIps(ListIpOptions... options);
-
-   /**
-    * Get details about the given IP address such as gateway and netmask. Different details are available
-    * on different platforms.
-    *
-    * @param ipAddress the ip address
-    * @return details about the given IP address
-    */
-   IpDetails getIp(String ipAddress);
-
-   /**
-    * Add an IP address to an server. The IP has to be free, but reserved to this account. You are able to list such addresses
-    * with listOwn() and reserve an address for this account by using take(). To find free ips you can use ip/listfree
-    * ip to an Xen-server you have to configure the server yourself, unless the ip was added during the c
-    * server (server/create). You can get detailed information such as gateway and netmask using the ip
-    *
-    * @param ipAddress the IP address to remove
-    * @param serverId  the server to add the IP address to
-    */
-   IpDetails addIpToServer(String ipAddress, String serverId);
-
-   /**
-    * Remove an IP address from a server. This does not release it back to GleSYS pool of free ips. The address will be
-    * kept on the account so that you can use it for other servers or the same server at a later time. To completely remove
-    * the IP address from this account, use removeIpFromServerAndRelease to do so
-    *
-    * @param ipAddress the IP address to remove
-    * @param serverId  the server to remove the IP address from
-    * @see #removeIpFromServerAndRelease
-    */
-   IpDetails removeIpFromServer(String ipAddress, String serverId);
-
-   /**
-    * Remove an IP address from a server and release it back to GleSYS pool of free ips.
-    *
-    * @param ipAddress the IP address to remove
-    * @param serverId  the server to remove the IP address from
-    * @see #removeIpFromServer
-    */
-   IpDetails removeIpFromServerAndRelease(String ipAddress, String serverId);
-
-   /**
-    * Sets PTR data for an IP. Use ip/listown or ip/details to get current PTR data
-    */
-   IpDetails setPtr(String ipAddress, String ptr);
-
-   /**
-    * Resets PTR data for an IP back to the default value
-    */
-   IpDetails resetPtr(String ipAddress);
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncApi.java
deleted file mode 100644
index 2e2a283..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncApi.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.IpDetails;
-import org.jclouds.glesys.options.ListIpOptions;
-import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.FormParams;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.SelectJson;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides asynchronous access to IP Addresses via their REST API.
- * <p/>
- *
- * @author Adrian Cole, Mattias Holmqvist, Adam Lowe
- * @see IpApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@RequestFilters(BasicAuthentication.class)
-public interface IpAsyncApi {
-   /**
-    * @see IpApi#listFree
-    */
-   @GET
-   @Path("/ip/listfree/ipversion/{ipversion}/datacenter/{datacenter}/platform/{platform}/format/json")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @SelectJson("ipaddresses")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<Set<String>> listFree(@PathParam("ipversion") int ipversion,
-                                          @PathParam("datacenter") String datacenter,
-                                          @PathParam("platform") String platform);
-
-   /**
-    * @see IpApi#take
-    */
-   @POST
-   @Path("/ip/take/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<IpDetails> take(@FormParam("ipaddress") String ipAddress);
-
-   /**
-    * @see IpApi#release
-    */
-   @POST
-   @Path("/ip/release/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<IpDetails> release(@FormParam("ipaddress") String ipAddress);
-
-   /**
-    * @see IpApi#listIps
-    */
-   @GET
-   @Path("/ip/listown/format/json")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @SelectJson("iplist")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<Set<IpDetails>> listIps(ListIpOptions... options);
-
-   /**
-    * @see IpApi#getIp
-    */
-   @GET
-   @Path("/ip/details/ipaddress/{ipaddress}/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<IpDetails> getIp(@PathParam("ipaddress") String ipAddress);
-
-   /**
-    * @see IpApi#addIpToServer
-    */
-   @POST
-   @Path("/ip/add/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<IpDetails> addIpToServer(@FormParam("ipaddress") String ipAddress,
-                                             @FormParam("serverid") String serverId);
-
-   /**
-    * @see IpApi#removeIpFromServer
-    */
-   @POST
-   @Path("/ip/remove/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<IpDetails> removeIpFromServer(@FormParam("ipaddress") String ipAddress,
-                                                  @FormParam("serverid") String serverId);
-
-   /**
-    * @see IpApi#removeIpFromServer
-    */
-   @POST
-   @FormParams(keys = "release", values = "true")
-   @Path("/ip/remove/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<IpDetails> removeIpFromServerAndRelease(@FormParam("ipaddress") String ipAddress,
-                                                            @FormParam("serverid") String serverId);
-
-   /**
-    * @see IpApi#setPtr
-    */
-   @POST
-   @Path("/ip/setptr/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<IpDetails> setPtr(@FormParam("ipaddress") String ipAddress,
-                                      @FormParam("data") String ptr);
-
-   /**
-    * @see IpApi#resetPtr
-    */
-   @POST
-   @Path("/ip/resetptr/format/json")
-   @SelectJson("details")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<IpDetails> resetPtr(@FormParam("ipaddress") String ipAddress);
-
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerApi.java
deleted file mode 100644
index 370974f..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerApi.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
-import org.jclouds.glesys.domain.Console;
-import org.jclouds.glesys.domain.OSTemplate;
-import org.jclouds.glesys.domain.ResourceUsage;
-import org.jclouds.glesys.domain.Server;
-import org.jclouds.glesys.domain.ServerDetails;
-import org.jclouds.glesys.domain.ServerLimit;
-import org.jclouds.glesys.domain.ServerSpec;
-import org.jclouds.glesys.domain.ServerStatus;
-import org.jclouds.glesys.options.CloneServerOptions;
-import org.jclouds.glesys.options.CreateServerOptions;
-import org.jclouds.glesys.options.DestroyServerOptions;
-import org.jclouds.glesys.options.EditServerOptions;
-import org.jclouds.glesys.options.ServerStatusOptions;
-
-import com.google.common.annotations.Beta;
-
-/**
- * Provides synchronous access to Server.
- * <p/>
- *
- * @author Adrian Cole
- * @author Adam Lowe
- * @see ServerAsyncApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
-public interface ServerApi {
-
-   /**
-    * Get a list of all servers on this account.
-    *
-    * @return an account's associated server objects.
-    */
-   Set<Server> listServers();
-
-   /**
-    * Get detailed information about a server such as hostname, hardware
-    * configuration (cpu, memory and disk), ip addresses, cost, transfer, os and
-    * more.
-    *
-    * @param id id of the server
-    * @return server or null if not found
-    */
-   ServerDetails getServerDetails(String id);
-
-   /**
-    * Get detailed information about a server status including up-time and
-    * hardware usage (cpu, disk, memory and bandwidth)
-    *
-    * @param id      id of the server
-    * @param options optional parameters
-    * @return the status of the server or null if not found
-    */
-   ServerStatus getServerStatus(String id, ServerStatusOptions... options);
-
-   /**
-    * Get detailed information about a server's limits (for OpenVZ only).
-    * <p/>
-    *
-    * @param id id of the server
-    * @return the requested information about the server or null if not found
-    */
-   Map<String, ServerLimit> getServerLimits(String id);
-
-   /**
-    * Get information about how to connect to a server via VNC
-    *
-    * @param id id of the server
-    * @return the requested information about the server or null if not found
-    */
-   Console getConsole(String id);
-
-   /**
-    * Get information about the OS templates available
-    *
-    * @return the set of information about each template
-    */
-   Set<OSTemplate> listTemplates();
-
-   /**
-    * Get information about valid arguments to #createServer for each platform
-    *
-    * @return a map of argument lists, keyed on platform
-    */
-   Map<String, AllowedArgumentsForCreateServer> getAllowedArgumentsForCreateServerByPlatform();
-
-   /**
-    * Reset the fail count for a server limit (for OpenVZ only).
-    *
-    * @param id   id of the server
-    * @param type the type of limit to reset
-    */
-   Map<String, ServerLimit> resetServerLimit(String id, String type);
-
-   /**
-    * Reboot a server
-    *
-    * @param id id of the server
-    */
-   ServerDetails rebootServer(String id);
-
-   /**
-    * Start a server
-    *
-    * @param id id of the server
-    */
-   ServerDetails startServer(String id);
-
-   /**
-    * Stop a server
-    *
-    * @param id id of the server
-    */
-   ServerDetails stopServer(String id);
-
-   /**
-    * hard stop a server
-    *
-    * @param id id of the server
-    */
-   ServerDetails hardStopServer(String id);
-
-   /**
-    * Create a new server
-    *
-    * @param hostname     the host name of the new server
-    * @param rootPassword the root password to use
-    * @param options      optional settings ex. description
-    */
-   @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
-   ServerDetails createServerWithHostnameAndRootPassword(ServerSpec serverSpec, String hostname, String rootPassword,
-         CreateServerOptions... options);
-
-   /**
-    * Edit the configuration of a server
-    *
-    * @param serverid the serverId of the server to edit
-    * @param options  the settings to change
-    */
-   ServerDetails editServer(String serverid, EditServerOptions... options);
-
-   /**
-    * Clone a server
-    *
-    * @param serverid the serverId of the server to clone
-    * @param hostname the new host name of the cloned server
-    * @param options  the settings to change
-    */
-   @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
-   ServerDetails cloneServer(String serverid, String hostname, CloneServerOptions... options);
-
-   /**
-    * Destroy a server
-    *
-    * @param id     the id of the server
-    * @param keepIp if DestroyServerOptions.keepIp(true) the servers ip will be retained for use in your GleSYS account
-    */
-   ServerDetails destroyServer(String id, DestroyServerOptions keepIp);
-
-   /**
-    * Reset the root password of a server
-    *
-    * @param id       the id of the server
-    * @param password the new password to use
-    */
-   ServerDetails resetPassword(String id, String password);
-
-   /**
-    * Return resource usage over time for server
-    *
-    * @param id       the id of the server
-    * @param resource the name of the resource to retrieve usage information for (e.g. "cpuusage")
-    * @param resolution the time-period to extract data for (one of "minute", "hour" or "day)
-    */
-   @Beta
-   // TODO: better name
-   ResourceUsage getResourceUsage(String id, String resource, String resolution);
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncApi.java b/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncApi.java
deleted file mode 100644
index 92a8ccd..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncApi.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
-import org.jclouds.glesys.domain.Console;
-import org.jclouds.glesys.domain.OSTemplate;
-import org.jclouds.glesys.domain.ResourceUsage;
-import org.jclouds.glesys.domain.Server;
-import org.jclouds.glesys.domain.ServerDetails;
-import org.jclouds.glesys.domain.ServerLimit;
-import org.jclouds.glesys.domain.ServerSpec;
-import org.jclouds.glesys.domain.ServerStatus;
-import org.jclouds.glesys.functions.ParseTemplatesFromHttpResponse;
-import org.jclouds.glesys.options.CloneServerOptions;
-import org.jclouds.glesys.options.CreateServerOptions;
-import org.jclouds.glesys.options.DestroyServerOptions;
-import org.jclouds.glesys.options.EditServerOptions;
-import org.jclouds.glesys.options.ServerStatusOptions;
-import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.FormParams;
-import org.jclouds.rest.annotations.MapBinder;
-import org.jclouds.rest.annotations.PayloadParam;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.SelectJson;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
-import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides asynchronous access to Server via their REST API.
- * <p/>
- * 
- * @author Adrian Cole
- * @author Adam Lowe
- * @see ServerApi
- * @see <a href="https://customer.glesys.com/api.php" />
- */
-@RequestFilters(BasicAuthentication.class)
-public interface ServerAsyncApi {
-
-   /**
-    * @see ServerApi#listServers
-    */
-   @POST
-   @Path("/server/list/format/json")
-   @SelectJson("servers")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<Set<Server>> listServers();
-
-   /**
-    * @see ServerApi#getServerDetails
-    */
-   @POST
-   @Path("/server/details/format/json")
-   @SelectJson("server")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @FormParams(keys = "includestate", values = "true")
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<ServerDetails> getServerDetails(@FormParam("serverid") String id);
-
-   /**
-    * @see ServerApi#getServerStatus
-    */
-   @POST
-   @Path("/server/status/format/json")
-   @SelectJson("server")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<ServerStatus> getServerStatus(@FormParam("serverid") String id, ServerStatusOptions... options);
-
-   /**
-    * @see ServerApi#getServerLimits
-    */
-   @POST
-   @Path("/server/limits/format/json")
-   @SelectJson("limits")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<SortedMap<String, ServerLimit>> getServerLimits(@FormParam("serverid") String id);
-
-   /**
-    * @see ServerApi#getConsole
-    */
-   @POST
-   @Path("/server/console/format/json")
-   @SelectJson("console")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<Console> getConsole(@FormParam("serverid") String id);
-
-   /**
-    * @see ServerApi#getAllowedArgumentsForCreateServerByPlatform
-    */
-   @GET
-   @Path("/server/allowedarguments/format/json")
-   @SelectJson("argumentslist")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Map<String, AllowedArgumentsForCreateServer>> getAllowedArgumentsForCreateServerByPlatform();
-
-   /**
-    * @see ServerApi#listTemplates
-    */
-   @GET
-   @Path("/server/templates/format/json")
-   @ResponseParser(ParseTemplatesFromHttpResponse.class)
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<Set<OSTemplate>> listTemplates();
-
-   /**
-    * @see ServerApi#stopServer
-    */
-   @POST
-   @Path("/server/resetlimit/format/json")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<SortedMap<String, ServerLimit>> resetServerLimit(@FormParam("serverid") String id,
-         @FormParam("type") String type);
-
-   /**
-    * @see ServerApi#rebootServer
-    */
-   @POST
-   @SelectJson("server")
-   @Path("/server/reboot/format/json")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<ServerDetails> rebootServer(@FormParam("serverid") String id);
-
-   /**
-    * @see ServerApi#startServer
-    */
-   @POST
-   @SelectJson("server")
-   @Path("/server/start/format/json")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<ServerDetails> startServer(@FormParam("serverid") String id);
-
-   /**
-    * @see ServerApi#stopServer
-    */
-   @POST
-   @SelectJson("server")
-   @Path("/server/stop/format/json")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<ServerDetails> stopServer(@FormParam("serverid") String id);
-
-   /**
-    * @see ServerApi#hardStopServer
-    */
-   @POST
-   @SelectJson("server")
-   @Path("/server/stop/format/json")
-   @FormParams(keys = "type", values = "hard")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<ServerDetails> hardStopServer(@FormParam("serverid") String id);
-
-   /**
-    * @see ServerApi#createServerWithHostnameAndRootPassword
-    */
-   @POST
-   @SelectJson("server")
-   @Path("/server/create/format/json")
-   @Consumes(MediaType.APPLICATION_JSON)
-   @MapBinder(CreateServerOptions.class)
-   ListenableFuture<ServerDetails> createServerWithHostnameAndRootPassword(ServerSpec serverSpec,
-         @PayloadParam("hostname") String hostname, @PayloadParam("rootpassword") String rootPassword,
-         CreateServerOptions... options);
-
-   /**
-    * @see ServerApi#cloneServer
-    */
-   @POST
-   @Path("/server/clone/format/json")
-   @SelectJson("server")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<ServerDetails> cloneServer(@FormParam("serverid") String serverid,
-         @FormParam("hostname") String hostname, CloneServerOptions... options);
-
-   /**
-    * @see ServerApi#editServer
-    */
-   @POST
-   @Path("/server/edit/format/json")
-   @SelectJson("server")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<ServerDetails> editServer(@FormParam("serverid") String serverid, EditServerOptions... options);
-
-   /**
-    * @see ServerApi#destroyServer
-    */
-   @POST
-   @Path("/server/destroy/format/json")
-   ListenableFuture<Void> destroyServer(@FormParam("serverid") String id, DestroyServerOptions keepIp);
-
-   /**
-    * @see ServerApi#resetPassword
-    */
-   @POST
-   @Path("/server/resetpassword/format/json")
-   @SelectJson("server")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<ServerDetails> resetPassword(@FormParam("serverid") String id, @FormParam("rootpassword") String password);
-
-   /**
-    * @see ServerApi#getResourceUsage
-    */
-   @POST
-   @Path("/server/resourceusage/format/json")
-   @SelectJson("usage")
-   @Consumes(MediaType.APPLICATION_JSON)
-   ListenableFuture<ResourceUsage> getResourceUsage(@FormParam("serverid") String id, @FormParam("resource") String resource,
-         @FormParam("resolution") String resolution);
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java b/labs/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java
deleted file mode 100644
index c03f109..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.functions;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Map;
-import java.util.Set;
-
-import javax.inject.Singleton;
-
-import org.jclouds.glesys.domain.OSTemplate;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.functions.ParseFirstJsonValueNamed;
-import org.jclouds.json.internal.GsonWrapper;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
-
-/**
- * @author Adrian Cole
- */
-@Singleton
-public class ParseTemplatesFromHttpResponse implements Function<HttpResponse, Set<OSTemplate>> {
-   private final ParseFirstJsonValueNamed<Map<String, Set<OSTemplate>>> parser;
-
-   @Inject
-   public ParseTemplatesFromHttpResponse(GsonWrapper gsonView) {
-      this.parser = new ParseFirstJsonValueNamed<Map<String, Set<OSTemplate>>>(checkNotNull(gsonView,
-               "gsonView"), new TypeLiteral<Map<String, Set<OSTemplate>>>() {
-      }, "templates");
-   }
-
-   public Set<OSTemplate> apply(HttpResponse response) {
-      checkNotNull(response, "response");
-      Map<String, Set<OSTemplate>> toParse = parser.apply(response);
-      checkNotNull(toParse, "parsed result from %s", response);
-      return ImmutableSet.copyOf(Iterables.concat(toParse.values()));
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java b/labs/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java
deleted file mode 100644
index b460d2e..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.functions.internal;
-
-import java.io.IOException;
-
-import org.jclouds.glesys.domain.GleSYSBoolean;
-import org.jclouds.glesys.domain.Server;
-
-import com.google.common.base.Objects;
-import com.google.gson.TypeAdapter;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonToken;
-import com.google.gson.stream.JsonWriter;
-
-/**
- * @author Adam Lowe
- */
-public class GleSYSTypeAdapters {
-
-   public static class ServerStateAdapter extends TypeAdapter<Server.State> {
-      @Override
-      public void write(JsonWriter writer, Server.State value) throws IOException {
-         writer.value(value.value());
-      }
-
-      @Override
-      public Server.State read(JsonReader reader) throws IOException {
-         return Server.State.fromValue(reader.nextString());
-      }
-   }
-
-   public static class GleSYSBooleanAdapter extends TypeAdapter<GleSYSBoolean> {
-
-      @Override
-      public void write(JsonWriter writer, GleSYSBoolean value) throws IOException {
-         writer.value(value.getValue() ? "yes" : "no");
-      }
-
-      @Override
-      public GleSYSBoolean read(JsonReader in) throws IOException {
-         if (in.peek() == JsonToken.BOOLEAN) {
-            return new GleSYSBoolean(in.nextBoolean());
-         } else if (in.peek() == JsonToken.NULL) {
-            return GleSYSBoolean.FALSE;
-         } else {
-            return new GleSYSBoolean(Objects.equal(in.nextString(), "yes"));
-         }
-      }
-
-   }
-
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java b/labs/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java
deleted file mode 100644
index 82afc0f..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.handlers;
-
-import java.io.IOException;
-
-import javax.inject.Singleton;
-
-import org.jclouds.http.HttpCommand;
-import org.jclouds.http.HttpErrorHandler;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.HttpResponseException;
-import org.jclouds.rest.AuthorizationException;
-import org.jclouds.rest.ResourceNotFoundException;
-import org.jclouds.util.Strings2;
-
-import com.google.common.base.Throwables;
-import com.google.common.io.Closeables;
-
-/**
- * This will parse and set an appropriate exception on the command object.
- * 
- * @author Adrian Cole
- * 
- */
-@Singleton
-public class GleSYSErrorHandler implements HttpErrorHandler {
-
-   public void handleError(HttpCommand command, HttpResponse response) {
-      // it is important to always read fully and close streams
-      String message = parseMessage(response);
-      Exception exception = message != null ? new HttpResponseException(command, response, message)
-            : new HttpResponseException(command, response);
-      try {
-         message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
-               response.getStatusLine());
-         switch (response.getStatusCode()) {
-         case 401:
-         case 403:
-            exception = new AuthorizationException(message, exception);
-            break;
-         case 400:
-            if (message.indexOf("Could not find") != -1) {
-               exception = new ResourceNotFoundException(message, exception);
-            }
-            break;
-         case 404:
-            exception = new ResourceNotFoundException(message, exception);
-            break;
-         case 500:
-            if (message.indexOf("Locked") != -1) {
-               exception = new IllegalStateException(message, exception);
-            }
-            break;
-         }
-      } finally {
-         if (response.getPayload() != null)
-            Closeables.closeQuietly(response.getPayload().getInput());
-         command.setException(exception);
-      }
-   }
-
-   public String parseMessage(HttpResponse response) {
-      if (response.getPayload() == null)
-         return null;
-      try {
-         return Strings2.toString(response.getPayload());
-      } catch (IOException e) {
-         throw new RuntimeException(e);
-      } finally {
-         try {
-            response.getPayload().getInput().close();
-         } catch (IOException e) {
-            Throwables.propagate(e);
-         }
-      }
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java
deleted file mode 100644
index 07f423a..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.options;
-
-/**
- * @author Adam Lowe
- */
-public class CloneServerOptions extends EditServerOptions {
-   public static class Builder {
-      /**
-       * @see org.jclouds.glesys.options.CloneServerOptions#diskSizeGB
-       */
-      public static CloneServerOptions diskSizeGB(int diskSizeGB) {
-         return CloneServerOptions.class.cast(new CloneServerOptions().diskSizeGB(diskSizeGB));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.CloneServerOptions#memorySizeMB
-       */
-      public static CloneServerOptions memorySizeMB(int memorySizeMB) {
-         return CloneServerOptions.class.cast(new CloneServerOptions().memorySizeMB(memorySizeMB));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.CloneServerOptions#cpuCores
-       */
-      public static CloneServerOptions cpucores(int cpucores) {
-         return CloneServerOptions.class.cast(new CloneServerOptions().cpuCores(cpucores));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.CloneServerOptions#transferGB
-       */
-      public static CloneServerOptions transferGB(int transferGB) {
-         return CloneServerOptions.class.cast(new CloneServerOptions().transferGB(transferGB));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditServerOptions#description
-       */
-      public static CloneServerOptions description(String description) {
-         return CloneServerOptions.class.cast(new CloneServerOptions().description(description));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.CloneServerOptions#dataCenter
-       */
-      public static CloneServerOptions dataCenter(String dataCenter) {
-         return new CloneServerOptions().dataCenter(dataCenter);
-      }
-   }
-
-   /**
-    * Configure which datacenter to create the clone in
-    */
-   public CloneServerOptions dataCenter(String dataCenter) {
-      formParameters.put("datacenter", dataCenter);
-      return this;
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/EditAccountOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/EditAccountOptions.java
deleted file mode 100644
index 4d2d164..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/options/EditAccountOptions.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.options;
-
-
-/**
- * @author Adam Lowe
- * @see <a href="https://customer.glesys.com/api.php?a=doc#email_editaccount" />
- */
-public class EditAccountOptions extends CreateAccountOptions {
-
-   public static class Builder {
-      /**
-       * @see org.jclouds.glesys.options.EditAccountOptions#antispamLevel
-       */
-      public static EditAccountOptions antispamLevel(int antispamLevel) {
-         return EditAccountOptions.class.cast(new EditAccountOptions().antispamLevel(antispamLevel));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditAccountOptions#antiVirus
-       */
-      public static EditAccountOptions antiVirus(boolean antiVirus) {
-         return EditAccountOptions.class.cast(new EditAccountOptions().antiVirus(antiVirus));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditAccountOptions#autorespond
-       */
-      public static EditAccountOptions autorespond(boolean autorespond) {
-         return EditAccountOptions.class.cast(new EditAccountOptions().autorespond(autorespond));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditAccountOptions#autorespondSaveEmail
-       */
-      public static EditAccountOptions autorespondSaveEmail(boolean autorespondSaveEmail) {
-         return EditAccountOptions.class.cast(new EditAccountOptions().autorespondSaveEmail(autorespondSaveEmail));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditAccountOptions#autorespondMessage
-       */
-      public static EditAccountOptions autorespondMessage(String autorespondMessage) {
-         return EditAccountOptions.class.cast(new EditAccountOptions().autorespondMessage(autorespondMessage));
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditAccountOptions#password
-       */
-      public static EditAccountOptions password(String password) {
-         return new EditAccountOptions().password(password);
-      }
-   }
-
-   /** Reset the password for this account */
-   public EditAccountOptions password(String password) {
-      formParameters.put("password", password);
-      return this;
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/EditRecordOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/EditRecordOptions.java
deleted file mode 100644
index be5b4de..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/options/EditRecordOptions.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.options;
-
-/**
- * @author Adam Lowe
- */
-public class EditRecordOptions extends AddRecordOptions {
-
-   public static class Builder {
-      /**
-       * @see EditRecordOptions#host
-       */
-      public static EditRecordOptions host(String host) {
-         return new EditRecordOptions().host(host);
-      }
-
-      /**
-       * @see EditRecordOptions#type
-       */
-      public static EditRecordOptions type(String type) {
-         return new EditRecordOptions().type(type);
-      }
-
-      /**
-       * @see EditRecordOptions#data
-       */
-      public static EditRecordOptions data(String data) {
-         return new EditRecordOptions().data(data);
-      }
-
-      /**
-       * @see EditRecordOptions#ttl
-       */
-      public static EditRecordOptions ttl(int ttl) {
-         return EditRecordOptions.class.cast(new EditRecordOptions().ttl(ttl));
-      }
-   }
-
-
-   /** Configure the hostname attached to this record */
-   public EditRecordOptions host(String host) {
-      formParameters.put("host", host);
-      return this;
-   }
-
-   /** Configure the type of record, ex. "A", "CNAME" or "MX"  */
-   public EditRecordOptions type(String type) {
-      formParameters.put("type", type);
-      return this;
-   }
-
-   /** Set the content of this record (depending on type, for an "A" record this would be an ip address) */
-   public EditRecordOptions data(String data) {
-      formParameters.put("data", data);
-      return this;
-   }
-}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/EditServerOptions.java b/labs/glesys/src/main/java/org/jclouds/glesys/options/EditServerOptions.java
deleted file mode 100644
index 3b9d4d1..0000000
--- a/labs/glesys/src/main/java/org/jclouds/glesys/options/EditServerOptions.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.options;
-
-import org.jclouds.http.options.BaseHttpRequestOptions;
-
-/**
- * 
- * @author Adam Lowe
- */
-public class EditServerOptions extends BaseHttpRequestOptions {
-
-   public static class Builder {
-      /**
-       * @see org.jclouds.glesys.options.EditServerOptions#diskSizeGB
-       */
-      public static EditServerOptions disksizeGB(int disksizeGB) {
-         return new EditServerOptions().diskSizeGB(disksizeGB);
-      }
-      
-      /**
-       * @see org.jclouds.glesys.options.EditServerOptions#memorySizeMB
-       */
-      public static EditServerOptions memorysizeMB(int memorysizeMB) {
-         return new EditServerOptions().memorySizeMB(memorysizeMB);
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditServerOptions#cpuCores
-       */
-      public static EditServerOptions cpucores(int cpucores) {
-         EditServerOptions options = new EditServerOptions();
-         return options.cpuCores(cpucores);
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditServerOptions#transferGB
-       */
-      public static EditServerOptions transferGB(int transferGB) {
-         return new EditServerOptions().transferGB(transferGB);
-      }
-      
-      /**
-       * @see org.jclouds.glesys.options.EditServerOptions#hostname
-       */
-      public static EditServerOptions hostname(String hostname) {
-         EditServerOptions options = new EditServerOptions();
-         return options.hostname(hostname);
-      }
-
-      /**
-       * @see org.jclouds.glesys.options.EditServerOptions#description
-       */
-      public static EditServerOptions description(String description) {
-         EditServerOptions options = new EditServerOptions();
-         return options.description(description);
-      }
-   }
-
-   /** Configure the size of the disk, in GB, of the server */
-   public EditServerOptions diskSizeGB(int diskSizeGB) {
-      formParameters.put("disksize", Integer.toString(diskSizeGB));
-      return this;
-   }
-
-   /** Configure the amount of RAM, in MB, allocated to the server */
-   public EditServerOptions memorySizeMB(int memorySizeMB) {
-      formParameters.put("memorysize", Integer.toString(memorySizeMB));
-      return this;
-   }
-
-   /** Configure the number of CPU cores allocated to the server */
-   public EditServerOptions cpuCores(int cpucores) {
-      formParameters.put("cpucores", Integer.toString(cpucores));
-      return this;
-   }
-
-   /** Configure the transfer setting for the server */
-   public EditServerOptions transferGB(int transferGB) {
-      formParameters.put("transfer", Integer.toString(transferGB));
-      return this;
-   }
-
-   /** Configure the host name of the server (must be unique within the GleSYS account) */
-   public EditServerOptions hostname(String hostname) {
-      formParameters.put("hostname", hostname);
-      return this;
-   }
-
-   /** Configure the description of the server */
-   public EditServerOptions description(String description) {
-      formParameters.put("description", description);
-      return this;
-   }
-
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncApiTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncApiTest.java
deleted file mode 100644
index db34cff..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncApiTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-
-import org.jclouds.http.HttpRequest;
-import org.jclouds.providers.ProviderMetadata;
-import org.jclouds.rest.internal.BaseAsyncApiTest;
-import org.jclouds.rest.internal.RestAnnotationProcessor;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import com.google.inject.TypeLiteral;
-
-/**
- * Tests behavior of {@code GleSYSAsyncApi}
- * 
- * @author Adrian Cole
- */
-// NOTE:without testName, this will not call @Before* and fail w/NPE during
-// surefire
-@Test(groups = "unit", testName = "GleSYSAsyncApiTest")
-public class GleSYSAsyncApiTest extends BaseAsyncApiTest<GleSYSAsyncApi> {
-   private GleSYSAsyncApi asyncApi;
-   private GleSYSApi syncApi;
-
-   @Override
-   public ProviderMetadata createProviderMetadata() {
-      return new GleSYSProviderMetadata();
-   }
-   
-   public void testSync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
-      assert syncApi.getServerApi() != null;
-      assert syncApi.getIpApi() != null;
-      assert syncApi.getArchiveApi() != null;
-      assert syncApi.getDomainApi() != null;
-   }
-
-   public void testAsync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
-      assert asyncApi.getServerApi() != null;
-      assert asyncApi.getIpApi() != null;
-      assert asyncApi.getArchiveApi() != null;
-      assert asyncApi.getDomainApi() != null;
-   }
-
-   @Override
-   protected TypeLiteral<RestAnnotationProcessor<GleSYSAsyncApi>> createTypeLiteral() {
-      return new TypeLiteral<RestAnnotationProcessor<GleSYSAsyncApi>>() {
-      };
-   }
-
-   @BeforeClass
-   @Override
-   protected void setupFactory() throws IOException {
-      super.setupFactory();
-      asyncApi = injector.getInstance(GleSYSAsyncApi.class);
-      syncApi = injector.getInstance(GleSYSApi.class);
-   }
-
-   @Override
-   protected void checkFilters(HttpRequest request) {
-
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java
deleted file mode 100644
index 0744fb6..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.compute;
-
-import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
-import static org.jclouds.compute.util.ComputeServiceUtils.getSpace;
-import static org.testng.Assert.assertEquals;
-
-import java.io.IOException;
-import java.util.Set;
-
-import org.jclouds.compute.domain.OsFamily;
-import org.jclouds.compute.domain.OsFamilyVersion64Bit;
-import org.jclouds.compute.domain.Template;
-import org.jclouds.compute.domain.Volume;
-import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest;
-import org.jclouds.glesys.compute.options.GleSYSTemplateOptions;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableSet;
-
-/**
- * 
- * @author Adrian Cole
- */
-@Test(groups = "live", testName = "GleSYSTemplateBuilderLiveTest")
-public class GleSYSTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
-
-   public GleSYSTemplateBuilderLiveTest() {
-      provider = "glesys";
-   }
-
-   // / allows us to break when a new os is added
-   @Override
-   protected Predicate<OsFamilyVersion64Bit> defineUnsupportedOperatingSystems() {
-      return Predicates.not(new Predicate<OsFamilyVersion64Bit>() {
-
-         @Override
-         public boolean apply(OsFamilyVersion64Bit input) {
-            switch (input.family) {
-            case UBUNTU:
-               return input.version.equals("")
-                     || input.version.equals("10.04")
-                     || input.version.equals("12.04")
-                     || ((input.version.equals("8.04") || input.version.equals("11.04") || input.version
-                           .equals("10.10")) && input.is64Bit);
-            case DEBIAN:
-               return input.version.equals("") || input.version.matches("[56].0");
-            case FEDORA:
-               return input.version.equals("") || input.version.equals("13") || input.version.equals("15");
-            case CENTOS:
-               return input.version.equals("") || input.version.equals("5") || input.version.equals("5.5")
-                     || input.version.equals("5.0") || input.version.equals("6.0");
-            case WINDOWS:
-               return input.version.equals("") || input.version.equals("2008")
-                     || (input.version.equals("2008 R2") && input.is64Bit);
-            default:
-               return false;
-            }
-         }
-
-      });
-   }
-
-   @Test
-   public void testDefaultTemplateBuilder() throws IOException {
-      Template defaultTemplate = view.getComputeService().templateBuilder().build();
-      assertEquals(defaultTemplate.getImage().getId(), "Ubuntu 12.04 LTS 64-bit");
-      assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "12.04");
-      assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
-      assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
-      assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
-      assertEquals(defaultTemplate.getHardware().getRam(), 512);
-      assertEquals(defaultTemplate.getHardware().getHypervisor(), "OpenVZ");
-      assertEquals(getSpace(defaultTemplate.getHardware()), 5.0d);
-      assertEquals(defaultTemplate.getHardware().getVolumes().get(0).getType(), Volume.Type.LOCAL);
-      // test that we bound the correct templateoptions in guice
-      assertEquals(defaultTemplate.getOptions().getClass(), GleSYSTemplateOptions.class);
-   }
-
-   @Override
-   protected Set<String> getIso3166Codes() {
-      return ImmutableSet.<String> of("NL-NH", "SE-N", "US-NY", "SE-AB");
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java
deleted file mode 100644
index 5ca80eb..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.compute.functions;
-
-import static org.jclouds.io.Payloads.newUrlEncodedFormPayload;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-
-import org.jclouds.compute.domain.HardwareBuilder;
-import org.jclouds.compute.domain.NodeMetadata;
-import org.jclouds.compute.domain.NodeMetadata.Status;
-import org.jclouds.compute.domain.NodeMetadataBuilder;
-import org.jclouds.compute.domain.OperatingSystem;
-import org.jclouds.compute.domain.OsFamily;
-import org.jclouds.compute.domain.Processor;
-import org.jclouds.compute.domain.Volume;
-import org.jclouds.compute.domain.internal.VolumeImpl;
-import org.jclouds.glesys.compute.internal.BaseGleSYSComputeServiceExpectTest;
-import org.jclouds.glesys.features.ServerApiExpectTest;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-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.ImmutableSet;
-
-/**
- * TODO
- * 
- */
-@Test(groups = "unit", testName = "ServerDetailsToNodeMetadataTest")
-public class ServerDetailsToNodeMetadataTest extends BaseGleSYSComputeServiceExpectTest {
-
-   @Test
-   public void testServerDetailsRequest() {
-
-      ServerDetailsToNodeMetadata toTest = injectorForKnownArgumentsAndConstantPassword(
-            ImmutableMap
-                  .<HttpRequest, HttpResponse> builder()
-                  .put(HttpRequest
-                        .builder()
-                        .method("POST")
-                        .endpoint("https://api.glesys.com/server/details/format/json")
-                        .addHeader("Accept", "application/json")
-                        .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                        .payload(
-                              newUrlEncodedFormPayload(ImmutableMultimap.<String, String> builder()
-                                    .put("serverid", "xm3276891").build())).build(),
-                        HttpResponse
-                              .builder()
-                              .statusCode(200)
-                              .payload(payloadFromResource("/server_details.json"))
-                              .build()).build()
-
-      ).getInstance(ServerDetailsToNodeMetadata.class);
-
-      NodeMetadata actual = toTest.apply(ServerApiExpectTest.expectedServerDetails());
-      assertNotNull(actual);
-
-      assertEquals(
-            actual.toString(),
-            new NodeMetadataBuilder()
-                  .ids("vz1840356")
-                  .name("test-email-jclouds")
-                  .hostname("test-email-jclouds")
-                  .group("glesys-s")
-                  .imageId("Ubuntu 10.04 LTS 32-bit")
-                  .operatingSystem(
-                        OperatingSystem.builder().name("Ubuntu 10.04 LTS 32-bit").family(OsFamily.UBUNTU).version("10.04")
-                              .is64Bit(false).description("Ubuntu 10.04 LTS 32-bit").build())
-                  .publicAddresses(ImmutableSet.of("31.192.231.254"))
-                  .hardware(
-                        new HardwareBuilder().ids("vz1840356").ram(512)
-                              .processors(ImmutableList.of(new Processor(1, 1.0)))
-                              .volumes(ImmutableList.<Volume> of(new VolumeImpl(5f, true, true))).hypervisor("OpenVZ")
-                              .build()).status(Status.RUNNING).build().toString());
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiExpectTest.java
deleted file mode 100644
index 6502cf2..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiExpectTest.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.List;
-
-import org.jclouds.glesys.domain.Archive;
-import org.jclouds.glesys.domain.ArchiveAllowedArguments;
-import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.HttpResponseException;
-import org.jclouds.rest.ResourceNotFoundException;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMultimap;
-
-/**
- * Tests parsing of {@code ArchiveAsyncApi}
- *
- * @author Adam Lowe
- */
-@Test(groups = "unit", testName = "ArchiveApiExpectTest")
-public class ArchiveApiExpectTest extends BaseGleSYSApiExpectTest {
-
-   public void testListArchivesWhenReponseIs2xx() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_list.json")).build())
-            .getArchiveApi();
-
-      List<Archive> expected = ImmutableList.of(
-            Archive.builder().username("xxxxx_test1").freeSize("20 GB").totalSize("30 GB").locked(false).build());
-
-      assertEquals(api.listArchives(), expected);
-   }
-
-   public void testListArchivesWhenResponseIs4xxReturnsEmpty() {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build()).getArchiveApi();
-
-      assertTrue(api.listArchives().isEmpty());
-   }
-
-   public void testArchiveDetailsWhenResponseIs2xx() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/details/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("username", "xxxxxx_test1").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build())
-            .getArchiveApi();
-
-      assertEquals(api.getArchive("xxxxxx_test1"), detailsInArchiveDetails());
-   }
-
-   private Archive detailsInArchiveDetails() {
-      return Archive.builder().username("xxxxxx_test1").freeSize("30 GB").totalSize("30 GB").locked(false).build();
-   }
-
-   public void testArchiveDetailsWhenResponseIs4xxReturnsNull() {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/details/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("username", "xxxxxx_test1").build(),
-            HttpResponse.builder().statusCode(404).build())
-            .getArchiveApi();
-      assertNull(api.getArchive("xxxxxx_test1"));
-   }
-
-   public void testCreateArchiveWhenResponseIs2xx() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/create/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParams(ImmutableMultimap.<String, String>builder()
-                             .put("username", "xxxxxx_test1")
-                             .put("size", "5")
-                             .put("password", "somepass").build()).build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build()).getArchiveApi();
-      assertEquals(api.createArchive("xxxxxx_test1", "somepass", 5), detailsInArchiveDetails());
-   }
-
-   public void testDeleteArchiveWhenResponseIs2xx() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/delete/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("username", "xxxxxx_test1").build(),
-            HttpResponse.builder().statusCode(200).build()).getArchiveApi();
-
-      api.deleteArchive("xxxxxx_test1");
-   }
-
-   @Test(expectedExceptions = {HttpResponseException.class})
-   public void testDeleteArchiveWhenResponseIs4xxThrows() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/delete/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("username", "xxxxxx_test1").build(),
-            HttpResponse.builder().statusCode(402).build()).getArchiveApi();
-      api.deleteArchive("xxxxxx_test1");
-   }
-
-   public void testResizeArchiveWhenResponseIs2xx() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/resize/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("username", "username1")
-                       .addFormParam("size", "5").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build()).getArchiveApi();
-
-      assertEquals(api.resizeArchive("username1", 5), detailsInArchiveDetails());
-   }
-
-   @Test(expectedExceptions = {ResourceNotFoundException.class})
-   public void testResizeArchiveWhenResponseIs4xxThrows() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/resize/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("username", "username1")
-                       .addFormParam("size", "5").build(),
-            HttpResponse.builder().statusCode(404).build()).getArchiveApi();
-
-      api.resizeArchive("username1", 5);
-   }
-
-   public void testChangeArchivePasswordWhenResponseIs2xx() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST")
-                       .endpoint("https://api.glesys.com/archive/changepassword/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("username", "username")
-                       .addFormParam("password", "newpass").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build()).getArchiveApi();
-      
-      assertEquals(api.changeArchivePassword("username", "newpass"), detailsInArchiveDetails());
-   }
-
-   @Test(expectedExceptions = {ResourceNotFoundException.class})
-   public void testChangeArchivePasswordWhenResponseIs4xxThrows() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST")
-                  .endpoint("https://api.glesys.com/archive/changepassword/format/json")
-                  .addHeader("Accept", "application/json")
-                  .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                  .addFormParam("username", "username")
-                  .addFormParam("password", "newpass").build(),
-            HttpResponse.builder().statusCode(404).build()).getArchiveApi();
-
-      api.changeArchivePassword("username", "newpass");
-   }
-
-   public void testGetArchiveAllowedArgumentsWhenResponseIs2xx() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET")
-                  .endpoint("https://api.glesys.com/archive/allowedarguments/format/json")
-                  .addHeader("Accept", "application/json")
-                  .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_allowed_arguments.json")).build()).getArchiveApi();
-      ArchiveAllowedArguments expected = ArchiveAllowedArguments.builder().archiveSizes(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000).build();
-
-      assertEquals(api.getArchiveAllowedArguments(), expected);
-   }
-
-   public void testGetArchiveAllowedArguments4xxWhenResponseIs2xx() throws Exception {
-      ArchiveApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET")
-                  .endpoint("https://api.glesys.com/archive/allowedarguments/format/json")
-                  .addHeader("Accept", "application/json")
-                  .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build()).getArchiveApi();
-
-      assertNull(api.getArchiveAllowedArguments());
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiLiveTest.java
deleted file mode 100644
index fe34a30..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiLiveTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.glesys.domain.Archive;
-import org.jclouds.glesys.domain.ArchiveAllowedArguments;
-import org.jclouds.glesys.internal.BaseGleSYSApiLiveTest;
-import org.jclouds.predicates.RetryablePredicate;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeGroups;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicate;
-
-/**
- * Tests behavior of {@code ArchiveApi}
- *
- * @author Adam Lowe
- */
-@Test(groups = "live", testName = "ArchiveApiLiveTest", singleThreaded = true)
-public class ArchiveApiLiveTest extends BaseGleSYSApiLiveTest {
-
-   @BeforeGroups(groups = {"live"})
-   public void setupContext() {
-      super.setupContext();
-      
-      api = gleContext.getApi().getArchiveApi();
-      archiveUser = gleContext.getIdentity().toLowerCase() + "_test9";
-      archiveCounter = new RetryablePredicate<Integer>(
-            new Predicate<Integer>() {
-               public boolean apply(Integer value){
-                  return api.listArchives().size() == value;
-               }
-            }, 30, 1, TimeUnit.SECONDS);
-   }
-   
-   @AfterClass(groups = { "integration", "live" })
-   protected void tearDownContext() {
-      int before = api.listArchives().size();
-      api.deleteArchive(archiveUser);
-      assertTrue(archiveCounter.apply(before - 1));
-
-      super.tearDownContext();
-   }
-
-   private ArchiveApi api;
-   private String archiveUser;
-   private RetryablePredicate<Integer> archiveCounter;
-
-   @Test
-   public void testAllowedArguments() throws Exception {
-      ArchiveAllowedArguments args = api.getArchiveAllowedArguments();
-      assertNotNull(args);
-      assertNotNull(args.getArchiveSizes());
-      assertTrue(args.getArchiveSizes().size() > 0);
-      
-      for (int size : args.getArchiveSizes()) {
-         assertTrue(size > 0);
-      }
-   }
-   
-   @Test
-   public void testCreateArchive() throws Exception {
-      try {
-         api.deleteArchive(archiveUser);
-      } catch(Exception ex) {
-      }
-      
-      int before = api.listArchives().size();
-      
-      api.createArchive(archiveUser, "password", 10);
-
-      assertTrue(archiveCounter.apply(before + 1));
-   }
-
-   @Test(dependsOnMethods = "testCreateArchive")
-   public void testArchiveDetails() throws Exception {
-      Archive details = api.getArchive(archiveUser);
-      assertEquals(details.getUsername(), archiveUser);
-   }
-
-   @Test(dependsOnMethods = "testCreateArchive")
-   public void testChangePassword() throws Exception {
-      api.changeArchivePassword(archiveUser, "newpassword");      
-      // TODO assert something useful!
-   }
-
-   @Test(dependsOnMethods = "testCreateArchive")
-   public void testResizeArchive() throws Exception {
-      api.resizeArchive(archiveUser, 20);
-
-      assertTrue(new RetryablePredicate<String>(
-            new Predicate<String>() {
-               public boolean apply(String value){
-                  return api.getArchive(archiveUser) != null && value.equals(api.getArchive(archiveUser).getTotalSize());
-               }
-            }, 30, 1, TimeUnit.SECONDS).apply("20 GB"));
-   }
-
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainApiExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainApiExpectTest.java
deleted file mode 100644
index 677afc8..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainApiExpectTest.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Set;
-
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.Domain;
-import org.jclouds.glesys.domain.DomainRecord;
-import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
-import org.jclouds.glesys.options.AddDomainOptions;
-import org.jclouds.glesys.options.EditRecordOptions;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.rest.ResourceNotFoundException;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-/**
- * Tests annotation parsing of {@code DomainAsyncApi}
- *
- * @author Adam Lowe
- */
-@Test(groups = "unit", testName = "DomainApiExpectTest")
-public class DomainApiExpectTest extends BaseGleSYSApiExpectTest {
-   
-   public void testListDomainsWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/domain_list.json")).build()).getDomainApi();
-
-      Domain expected =
-            Domain.builder().domainName("testglesys.jclouds.org").createTime(dateService.iso8601SecondsDateParse("2012-01-31T12:19:03+01:00")).build();
-
-      Domain actual = Iterables.getOnlyElement(api.listDomains());
-      assertEquals(expected.getDomainName(), actual.getDomainName());
-      assertEquals(expected.getCreateTime(), actual.getCreateTime());
-   }
-
-   public void testListDomainsWhenResponseIs4xxReturnsEmpty() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build()).getDomainApi();
-
-      assertTrue(api.listDomains().isEmpty());
-   }
-
-   public void testListDomainRecordsWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/listrecords/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "testglesys.jclouds.org").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/domain_list_records.json")).build()).getDomainApi();
-
-      Set<DomainRecord> expected = ImmutableSet.of(
-            DomainRecord.builder().id("224538").domainname("testglesys.jclouds.org").host("@").type("NS").data("ns1.namesystem.se.").ttl(3600).build(),
-            DomainRecord.builder().id("224539").domainname("testglesys.jclouds.org").host("@").type("NS").data("ns2.namesystem.se.").ttl(3600).build(),
-            DomainRecord.builder().id("224540").domainname("testglesys.jclouds.org").host("@").type("NS").data("ns3.namesystem.se.").ttl(3600).build(),
-            DomainRecord.builder().id("224541").domainname("testglesys.jclouds.org").host("@").type("A").data("127.0.0.1").ttl(3600).build(),
-            DomainRecord.builder().id("224542").domainname("testglesys.jclouds.org").host("www").type("A").data("127.0.0.1").ttl(3600).build(),
-            DomainRecord.builder().id("224543").domainname("testglesys.jclouds.org").host("mail").type("A").data("79.99.4.40").ttl(3600).build(),
-            DomainRecord.builder().id("224544").domainname("testglesys.jclouds.org").host("@").type("MX").data("10 mx01.glesys.se.").ttl(3600).build(),
-            DomainRecord.builder().id("224545").domainname("testglesys.jclouds.org").host("@").type("MX").data("20 mx02.glesys.se.").ttl(3600).build(),
-            DomainRecord.builder().id("224546").domainname("testglesys.jclouds.org").host("@").type("TXT").data("v=spf1 include:spf.glesys.se -all").ttl(3600).build()
-      );
-
-      Set<DomainRecord> actual = api.listRecords("testglesys.jclouds.org");
-
-      assertEquals(actual, expected);
-
-      for (DomainRecord result : actual) {
-         for (DomainRecord expect : expected) {
-            if (result.equals(expect)) {
-               assertEquals(result.toString(), expect.toString(), "Deep comparison using toString() failed!");
-            }
-         }
-      }
-   }
-
-   public void testListDomainRecordsWhenResponseIs4xxReturnsEmpty() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build()).getDomainApi();
-
-      assertTrue(api.listDomains().isEmpty());
-   }
-
-   public void testAddDomainRecordsWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/addrecord/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "jclouds.org")
-                       .addFormParam("type", "A")
-                       .addFormParam("host", "jclouds.org")
-                       .addFormParam("data", "").build(),
-            HttpResponse.builder().statusCode(200)
-                  .payload(payloadFromResourceWithContentType("/domain_record.json", MediaType.APPLICATION_JSON)).build())
-            .getDomainApi();
-
-      assertEquals(api.addRecord("jclouds.org", "jclouds.org", "A", ""), recordInDomainRecord());
-   }
-
-   protected DomainRecord recordInDomainRecord() {
-      return DomainRecord.builder().id("256151").domainname("cl13016-domain.jclouds.org").host("test").type("A").data("127.0.0.1").ttl(3600).build();
-   }
-
-   @Test(expectedExceptions = ResourceNotFoundException.class)
-   public void testAddDomainRecordsWhenResponseIs4xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/addrecord/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "jclouds.org")
-                       .addFormParam("type", "A")
-                       .addFormParam("host", "jclouds.org")
-                       .addFormParam("data", "").build(),
-            HttpResponse.builder().statusCode(404).build()).getDomainApi();
-
-      api.addRecord("jclouds.org", "jclouds.org", "A", "");
-   }
-
-   public void testEditDomainRecordsWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/updaterecord/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("recordid", "256151")
-                       .addFormParam("host", "somehost")
-                       .addFormParam("ttl", "1800").build(),
-            HttpResponse.builder().statusCode(200)
-                  .payload(payloadFromResourceWithContentType("/domain_record.json", MediaType.APPLICATION_JSON)).build())
-            .getDomainApi();
-
-      assertEquals(api.editRecord("256151", EditRecordOptions.Builder.host("somehost"), EditRecordOptions.Builder.ttl(1800)), recordInDomainRecord());
-   }
-
-   @Test(expectedExceptions = ResourceNotFoundException.class)
-   public void testEditDomainRecordsWhenResponseIs4xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-               HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/updaterecord/format/json")
-                          .addHeader("Accept", "application/json")
-                          .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                          .addFormParam("recordid", "256151")
-                          .addFormParam("host", "somehost")
-                          .addFormParam("ttl", "1800").build(),
-            HttpResponse.builder().statusCode(404).build()).getDomainApi();
-
-      api.editRecord("256151", EditRecordOptions.Builder.host("somehost"), EditRecordOptions.Builder.ttl(1800));
-   }
-
-   public void testDeleteDomainRecordsWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/deleterecord/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("recordid", "256151").build(),
-            HttpResponse.builder().statusCode(200)
-                  .payload(payloadFromResourceWithContentType("/domain_record.json", MediaType.APPLICATION_JSON)).build())
-            .getDomainApi();
-
-      api.deleteRecord("256151");
-   }
-
-   @Test(expectedExceptions = ResourceNotFoundException.class)
-   public void testDeleteDomainRecordsWhenResponseIs4xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/deleterecord/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("recordid", "256151").build(),
-            HttpResponse.builder().statusCode(404).build()).getDomainApi();
-
-      api.deleteRecord("256151");
-   }
-
-   public void testGetDomainWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/details/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "cl66666_x").build(),
-            HttpResponse.builder().statusCode(200)
-                  .payload(payloadFromResourceWithContentType("/domain_details.json", MediaType.APPLICATION_JSON)).build())
-            .getDomainApi();
-
-      assertEquals(api.getDomain("cl66666_x"), domainInDomainDetails());
-   }
-
-
-   public void testGetDomainWhenResponseIs4xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/details/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "cl66666_x").build(),
-            HttpResponse.builder().statusCode(404).build())
-            .getDomainApi();
-
-      assertNull(api.getDomain("cl66666_x"));
-   }
-
-   protected Domain domainInDomainDetails() {
-      return Domain.builder().domainName("cl13016-domain.jclouds.org").createTime(dateService.iso8601SecondsDateParse("2012-06-24T11:52:49+02:00")).recordCount(9).build();
-   }
-
-   public void testAddDomainWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/add/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "cl66666_x").build(),
-            HttpResponse.builder().statusCode(200)
-                  .payload(payloadFromResourceWithContentType("/domain_details.json", MediaType.APPLICATION_JSON)).build())
-            .getDomainApi();
-
-      assertEquals(api.addDomain("cl66666_x"), domainInDomainDetails());
-   }
-
-   public void testAddDomainWithOptsWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/add/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "cl66666_x")
-                       .addFormParam("primarynameserver", "ns1.somewhere.x")
-                       .addFormParam("expire", "1")
-                       .addFormParam("minimum", "1")
-                       .addFormParam("refresh", "1")
-                       .addFormParam("responsibleperson", "Tester.")
-                       .addFormParam("retry", "1")
-                       .addFormParam("ttl", "1").build(),
-            HttpResponse.builder().statusCode(200)
-                  .payload(payloadFromResourceWithContentType("/domain_details.json", MediaType.APPLICATION_JSON)).build())
-            .getDomainApi();
-      AddDomainOptions options = (AddDomainOptions) AddDomainOptions.Builder.primaryNameServer("ns1.somewhere.x")
-            .expire(1).minimum(1).refresh(1).responsiblePerson("Tester").retry(1).ttl(1);
-
-      assertEquals(api.addDomain("cl66666_x", options), domainInDomainDetails());
-   }
-
-   public void testEditDomainWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/edit/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "x").build(),
-            HttpResponse.builder().statusCode(200)
-                  .payload(payloadFromResourceWithContentType("/domain_details.json", MediaType.APPLICATION_JSON)).build())
-            .getDomainApi();
-
-      assertEquals(api.editDomain("x"), domainInDomainDetails());
-   }
-
-   @Test(expectedExceptions = {ResourceNotFoundException.class})
-   public void testEditDomainWhenResponseIs4xxThrows() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/edit/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "x").build(),
-            HttpResponse.builder().statusCode(404).build()).getDomainApi();
-
-      api.editDomain("x");
-   }
-
-   public void testDeleteDomainWhenResponseIs2xx() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/delete/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "x").build(),
-            HttpResponse.builder().statusCode(200).build()).getDomainApi();
-
-      api.deleteDomain("x");
-   }
-
-   @Test(expectedExceptions = {ResourceNotFoundException.class})
-   public void testDeleteDomainWhenResponseIs4xxThrows() throws Exception {
-      DomainApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/delete/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "x").build(),
-            HttpResponse.builder().statusCode(404).build()).getDomainApi();
-
-      api.deleteDomain("x");
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainApiLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainApiLiveTest.java
deleted file mode 100644
index 61cacf3..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/DomainApiLiveTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.glesys.domain.Domain;
-import org.jclouds.glesys.domain.DomainRecord;
-import org.jclouds.glesys.internal.BaseGleSYSApiLiveTest;
-import org.jclouds.glesys.options.DomainOptions;
-import org.jclouds.glesys.options.EditRecordOptions;
-import org.jclouds.predicates.RetryablePredicate;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicate;
-
-/**
- * Tests behavior of {@code DomainApi}
- *
- * @author Adam Lowe
- */
-@Test(groups = "live", testName = "DomainApiLiveTest", singleThreaded = true)
-public class DomainApiLiveTest extends BaseGleSYSApiLiveTest {
-   public String testDomain;
-
-   @BeforeGroups(groups = {"live"})
-   public void setupContext() {
-      super.setupContext();
-      testDomain =  identity.toLowerCase() + "-domain.jclouds.org";
-      api = gleContext.getApi().getDomainApi();
-      domainCounter = new RetryablePredicate<Integer>(
-            new Predicate<Integer>() {
-               public boolean apply(Integer value) {
-                  return api.listDomains().size() == value;
-               }
-            }, 30, 1, TimeUnit.SECONDS);
-      recordCounter = new RetryablePredicate<Integer>(
-            new Predicate<Integer>() {
-               public boolean apply(Integer value) {
-                  return api.listRecords(testDomain).size() == value;
-               }
-            }, 30, 1, TimeUnit.SECONDS);
-
-      try {
-         api.deleteDomain(testDomain);
-      } catch (Exception ex) {
-      }
-      
-      createDomain(testDomain);
-   }
-
-   @AfterGroups(groups = {"live"})
-   public void tearDownContext() {
-      int before = api.listDomains().size();
-      api.deleteDomain(testDomain);
-      assertTrue(domainCounter.apply(before - 1));
-   
-      super.tearDownContext();
-   }
-
-   private DomainApi api;
-   private RetryablePredicate<Integer> domainCounter;
-   private RetryablePredicate<Integer> recordCounter;
-
-   @Test
-   public void testGetDomain() throws Exception {
-      Domain domain = api.getDomain(testDomain);
-      assertNotNull(domain);
-      assertEquals(domain.getDomainName(), testDomain);
-      assertNotNull(domain.getCreateTime());
-   }
-   
-   @Test
-   public void testEditDomain() throws Exception {
-      api.editDomain(testDomain, DomainOptions.Builder.responsiblePerson("another-tester.jclouds.org."));
-      Domain domain = api.getDomain(testDomain);
-      assertEquals(domain.getResponsiblePerson(), "another-tester.jclouds.org.");
-   }
-
-   @Test
-   public void testCreateRecord() throws Exception {
-      int before = api.listRecords(testDomain).size();
-
-      api.addRecord(testDomain, "test", "A", "127.0.0.1");
-
-      assertTrue(recordCounter.apply(before + 1));
-
-      for(DomainRecord record : api.listRecords(testDomain)) {
-         if ("test".equals(record.getHost())) {
-            assertEquals(record.getType(), "A");
-            assertEquals(record.getData(), "127.0.0.1");
-         }
-      }
-   }
-
-   @Test
-   public void testEditRecord() throws Exception {
-      int before = api.listRecords(testDomain).size();
-
-      api.addRecord(testDomain, "testeditbefore", "A", "127.0.0.1");
-
-      assertTrue(recordCounter.apply(before + 1));
-
-      String recordId = null;
-      for(DomainRecord record : api.listRecords(testDomain)) {
-         if ("testeditbefore".equals(record.getHost())) {
-            assertEquals(record.getType(), "A");
-            assertEquals(record.getData(), "127.0.0.1");
-            recordId = record.getId();
-         }
-      }
-
-      assertNotNull(recordId);
-
-      api.editRecord(recordId, EditRecordOptions.Builder.host("testeditafter"));
-
-      boolean found = false;
-      for(DomainRecord record : api.listRecords(testDomain)) {
-         if (recordId.equals(record.getId())) {
-            assertEquals(record.getHost(), "testeditafter");
-            assertEquals(record.getType(), "A");
-            assertEquals(record.getData(), "127.0.0.1");
-            found = true;
-         }
-      }
-      assertTrue(found);
-   }
-
-   @Test
-   public void testDeleteRecord() throws Exception {
-      Set<DomainRecord> domainRecords = api.listRecords(testDomain);
-
-      int before = domainRecords.size();
-      
-      api.deleteRecord(domainRecords.iterator().next().getId());
-
-      assertTrue(recordCounter.apply(before - 1));
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/EmailApiExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/EmailApiExpectTest.java
deleted file mode 100644
index 9145784..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/EmailApiExpectTest.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Set;
-
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.EmailAccount;
-import org.jclouds.glesys.domain.EmailAlias;
-import org.jclouds.glesys.domain.EmailOverview;
-import org.jclouds.glesys.domain.EmailOverviewDomain;
-import org.jclouds.glesys.domain.EmailOverviewSummary;
-import org.jclouds.glesys.domain.EmailQuota;
-import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
-import org.jclouds.glesys.options.EditAccountOptions;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.rest.AuthorizationException;
-import org.jclouds.rest.ResourceNotFoundException;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-/**
- * Tests annotation parsing of {@code EmailApi}
- *
- * @author Adam Lowe
- */
-@Test(groups = "unit", testName = "EmailAsyncApiTest")
-public class EmailApiExpectTest extends BaseGleSYSApiExpectTest {
-
-   public void testListWhenResponseIs2xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "cl13016.test.jclouds.org").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_list.json")).build()).getEmailApi();
-
-      EmailAccount.Builder<?> builder = EmailAccount.builder().quota(EmailQuota.builder().max(200).unit("MB").build()).antispamLevel(3).antiVirus(true).autoRespond(false).autoRespondSaveEmail(true);
-      Set<EmailAccount> expected =
-            ImmutableSet.of(
-                  builder.account("test1@cl13016.test.jclouds.org").antispamLevel(3)
-                        .created(dateService.iso8601SecondsDateParse("2012-06-24T11:53:45+02:00")).build(),
-                  builder.account("test@cl13016.test.jclouds.org").antispamLevel(3)
-                        .created(dateService.iso8601SecondsDateParse("2012-06-21T11:26:09+02:00"))
-                        .modified(dateService.iso8601SecondsDateParse("2012-06-24T11:53:48+02:00")).build()
-            );
-
-      Set<EmailAccount> actual = api.listAccounts("cl13016.test.jclouds.org");
-      assertEquals(actual, expected);
-      assertEquals(Iterables.get(actual, 0).toString(), Iterables.get(expected, 0).toString());
-   }
-
-   public void testListWhenResponseIs404IsEmpty() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/list/format/json")
-                  .addHeader("Accept", "application/json")
-                  .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                  .addFormParam("domainname", "test").build(),
-            HttpResponse.builder().statusCode(404).build()).getEmailApi();
-
-      assertTrue(api.listAccounts("test").isEmpty());
-   }
-
-   public void testListAliasesWhenResponseIs2xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "cl13016.test.jclouds.org").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_list.json")).build()).getEmailApi();
-
-      EmailAlias expected = EmailAlias.builder().alias("test2@cl13016.test.jclouds.org").forwardTo("test2@cl13016.test.jclouds.org").build();
-      EmailAlias actual = Iterables.getOnlyElement(api.listAliases("cl13016.test.jclouds.org"));
-      assertEquals(actual, expected);
-   }
-
-   public void testListAliasesWhenResponseIs404IsEmpty() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("domainname", "test").build(),
-            HttpResponse.builder().statusCode(404).build()).getEmailApi();
-
-      assertTrue(api.listAliases("test").isEmpty());
-   }
-
-   public void testOverviewWhenResponseIs2xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/overview/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_overview.json")).build()).getEmailApi();
-
-      EmailOverviewSummary summary = EmailOverviewSummary.builder().accounts(2).maxAccounts(50).aliases(1).maxAliases(1000).build();
-      EmailOverviewDomain domain = EmailOverviewDomain.builder().domain("cl13016.test.jclouds.org").accounts(2).aliases(0).build();
-      EmailOverview expected = EmailOverview.builder().summary(summary).domains(domain).build();
-
-      assertEquals(api.getEmailOverview(), expected);
-   }
-
-   public void testOverviewWhenResponseIs404ReturnsNull() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/overview/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build()).getEmailApi();
-
-      assertNull(api.getEmailOverview());
-   }
-
-   public void testCreateAccountWhenResponseIs2xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/createaccount/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("emailaccount", "test@jclouds.org")
-                       .addFormParam("password", "newpass").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/email_details.json", MediaType.APPLICATION_JSON)).build())
-            .getEmailApi();
-
-      assertEquals(api.createAccount("test@jclouds.org", "newpass").toString(), getEmailAccountInDetails().toString());
-   }
-
-   public void testEditAccountWhenResponseIs2xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/editaccount/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("emailaccount", "test@jclouds.org")
-                       .addFormParam("password", "anotherpass").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/email_details.json", MediaType.APPLICATION_JSON)).build())
-            .getEmailApi();
-
-      assertEquals(api.editAccount("test@jclouds.org", EditAccountOptions.Builder.password("anotherpass")).toString(), getEmailAccountInDetails().toString());
-   }
-
-   @Test(expectedExceptions = ResourceNotFoundException.class)
-   public void testEditAccountWhenResponseIs4xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/editaccount/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("emailaccount", "test@jclouds.org")
-                       .addFormParam("password", "anotherpass").build(),
-            HttpResponse.builder().statusCode(404).build())
-            .getEmailApi();
-
-      assertEquals(api.editAccount("test@jclouds.org", EditAccountOptions.Builder.password("anotherpass")).toString(), getEmailAccountInDetails().toString());
-   }
-
-   private EmailAccount getEmailAccountInDetails() {
-      return EmailAccount.builder().account("test@CL13016.jclouds.org")
-            .antispamLevel(3)
-            .antiVirus(true)
-            .autoRespondSaveEmail(true)
-            .created(dateService.iso8601SecondsDateParse("2012-06-20T12:01:01+02:00"))
-            .quota(EmailQuota.builder().max(200).unit("MB").build()).build();
-   }
-
-   @Test(expectedExceptions = {ResourceNotFoundException.class})
-   public void testCreateAccountWhenResponseIs4xxThrows() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/createaccount/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("emailaccount", "test@jclouds.org")
-                       .addFormParam("password", "newpass").build(),
-            HttpResponse.builder().statusCode(404).build()).getEmailApi();
-
-      api.createAccount("test@jclouds.org", "newpass");
-   }
-
-   public void testCreateAliasWhenResponseIs2xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/createalias/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("emailalias", "test2@jclouds.org")
-                       .addFormParam("goto", "test@jclouds.org").build(),
-            HttpResponse.builder().statusCode(200).build()).getEmailApi();
-
-      api.createAlias("test2@jclouds.org", "test@jclouds.org");
-   }
-
-   @Test(expectedExceptions = {AuthorizationException.class})
-   public void testCreateAliasWhenResponseIs4xxThrows() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/createalias/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("emailalias", "test2@jclouds.org")
-                       .addFormParam("goto", "test@jclouds.org").build(),
-            HttpResponse.builder().statusCode(401).build()).getEmailApi();
-
-      api.createAlias("test2@jclouds.org", "test@jclouds.org");
-   }
-
-   public void testEditAliasWhenResponseIs2xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/editalias/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("emailalias", "test2@jclouds.org")
-                       .addFormParam("goto", "test@jclouds.org").build(),
-            HttpResponse.builder().statusCode(200).build()).getEmailApi();
-
-      api.editAlias("test2@jclouds.org", "test@jclouds.org");
-   }
-
-   @Test(expectedExceptions = {ResourceNotFoundException.class})
-   public void testEditAliasWhenResponseIs4xxThrows() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/editalias/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("emailalias", "test2@jclouds.org")
-                       .addFormParam("goto", "test@jclouds.org").build(),
-            HttpResponse.builder().statusCode(404).build()).getEmailApi();
-
-      api.editAlias("test2@jclouds.org", "test@jclouds.org");
-   }
-
-   public void testDeleteWhenResponseIs2xx() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/delete/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("email", "test2@jclouds.org").build(),
-            HttpResponse.builder().statusCode(200).build()).getEmailApi();
-
-      api.delete("test2@jclouds.org");
-   }
-
-   @Test(expectedExceptions = {ResourceNotFoundException.class})
-   public void testDeleteWhenResponseIs4xxThrows() throws Exception {
-      EmailApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/delete/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("email", "test2@jclouds.org").build(),
-            HttpResponse.builder().statusCode(404).build()).getEmailApi();
-
-      api.delete("test2@jclouds.org");
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/EmailApiLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/EmailApiLiveTest.java
deleted file mode 100644
index d050cab..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/EmailApiLiveTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.glesys.domain.EmailAccount;
-import org.jclouds.glesys.domain.EmailAlias;
-import org.jclouds.glesys.domain.EmailOverview;
-import org.jclouds.glesys.domain.EmailOverviewDomain;
-import org.jclouds.glesys.internal.BaseGleSYSApiWithAServerLiveTest;
-import org.jclouds.glesys.options.CreateAccountOptions;
-import org.jclouds.glesys.options.EditAccountOptions;
-import org.jclouds.predicates.RetryablePredicate;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-
-/**
- * Tests behavior of {@code EmailApi}
- *
- * @author Adam Lowe
- */
-@Test(groups = "live", testName = "EmailApiLiveTest", singleThreaded = true)
-public class EmailApiLiveTest extends BaseGleSYSApiWithAServerLiveTest {
-
-   @BeforeGroups(groups = {"live"})
-   public void setupDomains() {
-      testDomain = identity + ".test.jclouds.org";
-      api = gleContext.getApi().getEmailApi();
-
-      createDomain(testDomain);
-
-      emailAccountCounter = new RetryablePredicate<Integer>(
-            new Predicate<Integer>() {
-               public boolean apply(Integer value) {
-                  return api.listAccounts(testDomain).size() == value;
-               }
-            }, 180, 5, TimeUnit.SECONDS);
-
-      assertTrue(emailAccountCounter.apply(0));
-      
-      try {
-         api.delete("test2@" + testDomain);
-      } catch(Exception e) {
-      }
-   }
-
-   @AfterGroups(groups = {"live"})
-   public void tearDownDomains() {
-      api.delete("test@" + testDomain);
-      api.delete("test1@" + testDomain);
-      assertTrue(emailAccountCounter.apply(0));
-      gleContext.getApi().getDomainApi().deleteDomain(testDomain);
-   }
-
-   private EmailApi api;
-   private String testDomain;
-   private RetryablePredicate<Integer> emailAccountCounter;
-
-   @Test
-   public void testCreateEmail() {
-      api.createAccount("test@" + testDomain, "password",
-            CreateAccountOptions.Builder.antiVirus(true).autorespond(true).autorespondMessage("out of office"));
-
-      assertTrue(emailAccountCounter.apply(1));
-
-      api.createAccount("test1@" + testDomain, "password");
-
-      assertTrue(emailAccountCounter.apply(2));
-   }
-
-   @Test(dependsOnMethods = "testCreateEmail")
-   public void testAliases() {
-      assertTrue(api.listAliases(testDomain).isEmpty());
-
-      EmailAlias alias = api.createAlias("test2@" + testDomain, "test@" + testDomain);
-      assertEquals(alias.getAlias(), "test2@" + testDomain);
-      assertEquals(alias.getForwardTo(), "test@" + testDomain);
-
-      EmailAlias aliasFromList = Iterables.getOnlyElement(api.listAliases(testDomain));
-      assertEquals(aliasFromList, alias);
-      
-      EmailOverview overview = api.getEmailOverview();
-      assertTrue(overview.getSummary().getAliases() == 1);
-
-      alias = api.editAlias("test2@" + testDomain, "test1@" + testDomain);
-      overview = api.getEmailOverview();
-      assertTrue(overview.getSummary().getAliases() == 1);
-      
-      aliasFromList = Iterables.getOnlyElement(api.listAliases(testDomain));
-      assertEquals(aliasFromList, alias);
-
-      api.delete("test2@" + testDomain);
-      overview = api.getEmailOverview();
-      assertTrue(overview.getSummary().getAliases() == 0);
-   }
-
-   @Test(dependsOnMethods = "testCreateEmail")
-   public void testOverview() throws Exception {
-      EmailOverview overview = api.getEmailOverview();
-      assertNotNull(overview.getSummary());
-      assertTrue(overview.getSummary().getAccounts() > 0);
-      assertTrue(overview.getSummary().getAliases() > -1);
-      assertTrue(overview.getSummary().getMaxAccounts() > 0);
-      assertTrue(overview.getSummary().getMaxAliases() > 0);
-      assertNotNull(overview.getDomains());
-      assertFalse(overview.getDomains().isEmpty());
-
-      EmailOverviewDomain domain = EmailOverviewDomain.builder().domain(testDomain).accounts(1).build();
-      assertTrue(overview.getDomains().contains(domain));
-   }
-
-   @Test(dependsOnMethods = "testCreateEmail")
-   public void testListAccounts() throws Exception {
-      Set<EmailAccount> accounts = api.listAccounts(testDomain);
-      assertTrue(accounts.size() >= 1);
-   }
-
-   @Test(dependsOnMethods = "testCreateEmail")
-   public void testEditAccount() throws Exception {
-      Set<EmailAccount> accounts = api.listAccounts(testDomain);
-      for (EmailAccount account : accounts) {
-         if (account.getAccount().equals("test@" + testDomain)) {
-            assertTrue(account.isAntiVirus());
-         }
-      }
-
-      api.editAccount("test@" + testDomain, EditAccountOptions.Builder.antiVirus(false));
-
-      accounts = api.listAccounts(testDomain);
-      for (EmailAccount account : accounts) {
-         if (account.getAccount().equals("test@" + testDomain)) {
-            assertFalse(account.isAntiVirus());
-         }
-      }
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/IpApiExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/IpApiExpectTest.java
deleted file mode 100644
index e256def..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/IpApiExpectTest.java
+++ /dev/null
@@ -1,309 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static java.util.Collections.emptySet;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.Cost;
-import org.jclouds.glesys.domain.IpDetails;
-import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
-import org.jclouds.glesys.parse.ParseIpAddressFromResponseTest;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.HttpResponseException;
-import org.jclouds.rest.AuthorizationException;
-import org.jclouds.rest.ResourceNotFoundException;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableSet;
-
-/**
- * Allows us to test a api via its side effects.
- *
- * @author Adrian Cole, Adam Lowe
- */
-@Test(groups = "unit", testName = "IpApiExpectTest")
-public class IpApiExpectTest extends BaseGleSYSApiExpectTest {
-
-   public void testListIpsWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/listown/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_list_own.json")).build())
-            .getIpApi();
-
-      IpDetails.Builder<?> builder = IpDetails.builder().datacenter("Falkenberg").version4().reserved(true)
-            .platform("OpenVZ")
-            .nameServers("79.99.4.100", "79.99.4.101")
-            .cost(Cost.builder().amount(2.0).currency("EUR").timePeriod("month").build());
-
-      assertEquals(api.listIps().toString(), ImmutableSet.of(
-            builder.ptr("31-192-230-68-static.serverhotell.net.").address("31.192.230.68").serverId(null).build(),
-            builder.ptr("31-192-231-148-static.serverhotell.net.").address("31.192.231.148").serverId("vz1609110").build()).toString());
-   }
-
-   public void testListIpsWhenResponseIs4xxReturnsEmpty() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/listown/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build()).getIpApi();
-
-      assertTrue(api.listIps().isEmpty());
-   }
-
-   public void testGetIpDetailsWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/details/ipaddress/31.192.227.113/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_get_details.json")).build())
-            .getIpApi();
-
-      assertEquals(api.getIp("31.192.227.113"), getIpInIpDetails());
-   }
-
-   protected IpDetails getIpInIpDetails() {
-      return IpDetails.builder().datacenter("Falkenberg").version4()
-            .platform("OpenVZ").ptr("31-192-227-113-static.serverhotell.net.")
-            .nameServers("79.99.4.100", "79.99.4.101")
-            .address("31.192.227.113")
-            .cost(Cost.builder().amount(2.0).currency("EUR").timePeriod("month").build()).build();
-   }
-
-   public void testGetIpDetailsWhenResponseIs4xxReturnsNull() {
-
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/details/ipaddress/31.192.227.37/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build()).getIpApi();
-
-      assertEquals(api.getIp("31.192.227.37"), null);
-   }
-
-   public void testTakeWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/take/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "46.21.105.186").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_take.json")).build())
-            .getIpApi();
-
-      api.take("46.21.105.186");
-   }
-
-   @Test(expectedExceptions = HttpResponseException.class)
-   public void testTakeWhenResponseIs4xxThrowsResponseException() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/take/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "46.21.105.186").build(),
-            HttpResponse.builder().statusCode(400).build()).getIpApi();
-      api.take("46.21.105.186");
-   }
-
-   public void testReleaseWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/release/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "46.21.105.186").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_release.json")).build())
-            .getIpApi();
-
-      api.release("46.21.105.186");
-   }
-
-   @Test(expectedExceptions = ResourceNotFoundException.class)
-   public void testReleaseWhenResponseIs4xxThrowsResponseException() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/release/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "46.21.105.186").build(),
-            HttpResponse.builder().statusCode(404).build())
-            .getIpApi();
-
-      api.release("46.21.105.186");
-   }
-
-   public void testListFreeWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/listfree/ipversion/4/datacenter/Falkenberg/platform/OpenVZ/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_list_free.json")).build())
-            .getIpApi();
-
-      assertEquals(api.listFree(4, "Falkenberg", "OpenVZ"), ParseIpAddressFromResponseTest.EXPECTED_IPS);
-   }
-
-   public void testListFreeWhenResponseIs404ReturnsEmptySet() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/listfree/ipversion/6/datacenter/Falkenberg/platform/OpenVZ/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build())
-            .getIpApi();
-
-      assertEquals(api.listFree(6, "Falkenberg", "OpenVZ"), emptySet());
-   }
-
-   public void testAddWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/add/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "31.192.227.37")
-                       .addFormParam("serverid", "vz1946889").build(),
-            HttpResponse.builder().statusCode(200).build())
-            .getIpApi();
-
-      api.addIpToServer("31.192.227.37", "vz1946889");
-   }
-
-   @Test(expectedExceptions = AuthorizationException.class)
-   public void testAddWhenResponseIs4xxThrowsHttpException() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/add/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "31.192.227.37")
-                       .addFormParam("serverid", "vz1946889").build(),
-            HttpResponse.builder().statusCode(401).build())
-            .getIpApi();
-      api.addIpToServer("31.192.227.37", "vz1946889");
-   }
-
-   public void testRemoveWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/remove/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "31.192.227.37")
-                       .addFormParam("serverid", "vz1946889").build(),
-            HttpResponse.builder().statusCode(200).build())
-            .getIpApi();
-
-      api.removeIpFromServer("31.192.227.37", "vz1946889");
-   }
-
-   @Test(expectedExceptions = HttpResponseException.class)
-   public void testRemoveWhenResponseIs4xxThrowsHttpException() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/remove/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "31.192.227.37")
-                       .addFormParam("serverid", "vz1946889").build(),
-            HttpResponse.builder().statusCode(400).build())
-            .getIpApi();
-
-      api.removeIpFromServer("31.192.227.37", "vz1946889");
-   }
-
-   public void testRemoveAndReleaseWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/remove/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("release", "true")
-                       .addFormParam("ipaddress", "31.192.227.37")
-                       .addFormParam("serverid", "vz1946889").build(),
-            HttpResponse.builder().statusCode(200).build())
-            .getIpApi();
-
-      api.removeIpFromServerAndRelease("31.192.227.37", "vz1946889");
-   }
-
-   @Test(expectedExceptions = HttpResponseException.class)
-   public void testRemoveAndReleaseWhenResponseIs4xxThrowsHttpException() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/remove/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("release", "true")
-                       .addFormParam("ipaddress", "31.192.227.37")
-                       .addFormParam("serverid", "vz1946889").build(),
-            HttpResponse.builder().statusCode(400).build())
-            .getIpApi();
-
-      api.removeIpFromServerAndRelease("31.192.227.37", "vz1946889");
-   }
-
-   public void testSetPrtWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/setptr/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "31.192.227.37")
-                       .addFormParam("data", "sommeptr.").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/ip_get_details.json", MediaType.APPLICATION_JSON)).build())
-            .getIpApi();
-
-      assertEquals(api.setPtr("31.192.227.37", "sommeptr."), getIpInIpDetails());
-   }
-
-   @Test(expectedExceptions = ResourceNotFoundException.class)
-   public void testSetPtrWhenResponseIs4xxThrowsHttpException() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/setptr/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "31.192.227.37")
-                       .addFormParam("data", "sommeptr.").build(),
-            HttpResponse.builder().statusCode(404).build())
-            .getIpApi();
-
-      api.setPtr("31.192.227.37", "sommeptr.");
-   }
-
-   public void testResetPrtWhenResponseIs2xx() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/resetptr/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "31.192.227.37").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/ip_get_details.json", MediaType.APPLICATION_JSON)).build())
-            .getIpApi();
-
-      assertEquals(api.resetPtr("31.192.227.37"), getIpInIpDetails());
-   }
-
-   @Test(expectedExceptions = AuthorizationException.class)
-   public void testResetPtrWhenResponseIs4xxThrowsHttpException() {
-      IpApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/resetptr/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("ipaddress", "31.192.227.37").build(),
-            HttpResponse.builder().statusCode(401).build())
-            .getIpApi();
-
-      api.resetPtr("31.192.227.37");
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/IpApiLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/IpApiLiveTest.java
deleted file mode 100644
index f07240e..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/IpApiLiveTest.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Set;
-
-import org.jclouds.glesys.domain.IpDetails;
-import org.jclouds.glesys.internal.BaseGleSYSApiWithAServerLiveTest;
-import org.jclouds.glesys.options.ListIpOptions;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-
-/**
- * Tests behavior of {@code IpApi}
- *
- * @author Adrian Cole, Mattias Holmqvist
- */
-@Test(groups = "live", testName = "IpApiLiveTest", singleThreaded = true)
-public class IpApiLiveTest extends BaseGleSYSApiWithAServerLiveTest {
-
-   @BeforeMethod
-   public void setupApi() {
-      api = gleContext.getApi().getIpApi();
-   }
-
-   @AfterGroups(groups = {"live"})
-   public void releaseIp() {
-      if (reservedIp != null) {
-         api.release(reservedIp.getAddress());
-      }
-   }
-
-   private IpApi api;
-   private IpDetails reservedIp;
-
-   @Test
-   public void testListFree() throws Exception {
-      Set<String> freeIps = api.listFree(4, "Falkenberg", "Xen");
-      assertFalse(freeIps.isEmpty());
-   }
-
-   @Test
-   public void reserveIp() throws Exception {
-      Set<String> openVzIps = api.listFree(4, "Falkenberg", "OpenVZ");
-      assertFalse(openVzIps.isEmpty());
-      reservedIp = api.take(Iterables.get(openVzIps, 0));
-      assertTrue(reservedIp.isReserved());
-      checkOpenVZDefailsInFalkenberg(reservedIp);
-   }
-
-   @Test(dependsOnMethods = "reserveIp")
-   public void reserveAndReleaseIp() throws Exception {
-      IpDetails details = api.release(reservedIp.getAddress());
-      assertEquals(details.getAddress(), reservedIp.getAddress());
-      assertFalse(details.isReserved());
-      
-      // reserve an address again!
-      reserveIp();
-   }
-
-   @Test(dependsOnMethods = "reserveIp")
-   public void testList() throws Exception {
-      Set<IpDetails> ownIps = api.listIps();
-      assertTrue(ownIps.contains(reservedIp));
-      ownIps = api.listIps(ListIpOptions.Builder.datacenter(reservedIp.getDatacenter()));
-      assertTrue(ownIps.contains(reservedIp));
-      ownIps = api.listIps(ListIpOptions.Builder.platform(reservedIp.getPlatform()));
-      assertTrue(ownIps.contains(reservedIp));
-      ownIps = api.listIps(ListIpOptions.Builder.ipVersion(reservedIp.getVersion()));
-      assertTrue(ownIps.contains(reservedIp));
-
-      ownIps = api.listIps(ListIpOptions.Builder.datacenter(reservedIp.getDatacenter()),
-            ListIpOptions.Builder.platform(reservedIp.getPlatform()),
-            ListIpOptions.Builder.ipVersion(reservedIp.getVersion()));
-      assertTrue(ownIps.contains(reservedIp));
-
-      ownIps = api.listIps(ListIpOptions.Builder.serverId("xmthisisnotaserverid"));
-      assertTrue(ownIps.isEmpty());
-   }
-   
-   private void checkOpenVZDefailsInFalkenberg(IpDetails ipDetails) {
-      assertEquals(ipDetails.getDatacenter(), "Falkenberg");
-      assertEquals(ipDetails.getPlatform(), "OpenVZ");
-      assertEquals(ipDetails.getVersion(), 4);
-      assertFalse(ipDetails.getPtr().isEmpty());
-      // broadcast, gateway and netmask are null for OpenVZ
-      assertFalse(ipDetails.getNameServers().isEmpty());
-   }
-   
-   @Test
-   public void testGetOpenVZDetails() throws Exception {
-      Set<String> openVzIps = api.listFree(4, "Falkenberg", "OpenVZ");
-      assertFalse(openVzIps.isEmpty());
-      String openVzIp = openVzIps.iterator().next();
-      IpDetails ipDetails = api.getIp(openVzIp);
-      checkOpenVZDefailsInFalkenberg(ipDetails);
-      assertEquals(ipDetails.getAddress(), openVzIp);
-   }
-
-   @Test
-   public void testGetXenDetails() throws Exception {
-      Set<String> xenVzIps = api.listFree(4, "Falkenberg", "Xen");
-      assertFalse(xenVzIps.isEmpty());
-      String xenIp = xenVzIps.iterator().next();
-      IpDetails ipDetails = api.getIp(xenIp);
-      assertEquals(ipDetails.getDatacenter(), "Falkenberg");
-      assertEquals(ipDetails.getPlatform(), "Xen");
-      assertEquals(ipDetails.getVersion(), 4);
-      assertEquals(ipDetails.getAddress(), xenIp);
-      assertFalse(ipDetails.getPtr().isEmpty());
-      assertNotNull(ipDetails.getBroadcast());
-      assertNotNull(ipDetails.getGateway());
-      assertNotNull(ipDetails.getNetmask());
-      assertFalse(ipDetails.getNameServers().isEmpty());
-   }
-
-   @Test(dependsOnMethods = "reserveIp")
-   public void testPtrSetReset() throws Exception {
-      IpDetails original = reservedIp;
-
-      IpDetails modified = api.setPtr(reservedIp.getAddress(), "wibble.");
-      IpDetails modified2 = api.getIp(reservedIp.getAddress());
-
-      assertEquals(modified.getPtr(), "wibble.");
-      assertEquals(modified2, modified);
-      
-      reservedIp = api.resetPtr(reservedIp.getAddress());
-      
-      assertEquals(reservedIp, original);
-  }
-
-   @Test(dependsOnMethods = "reserveIp")
-   public void testAddRemove() throws Exception {
-      IpDetails added = api.addIpToServer(reservedIp.getAddress(), serverId);
-
-      assertEquals(added.getAddress(), reservedIp.getAddress());
-      assertEquals(added.getPtr(), reservedIp.getPtr());
-      assertEquals(added.getServerId(), serverId);
-      
-      IpDetails again = api.getIp(reservedIp.getAddress());
-      assertEquals(again, added);
-
-      IpDetails removed = api.removeIpFromServer(reservedIp.getAddress(), serverId);
-      assertEquals(removed, added.toBuilder().serverId(null).build());
-
-      assertEquals(removed, reservedIp);
-
-      Set<String> openVzIps = Sets.newHashSet(api.listFree(4, "Falkenberg", "OpenVZ"));
-      openVzIps.remove(reservedIp.getAddress());
-      assertFalse(openVzIps.isEmpty());
-      
-      added = api.addIpToServer(reservedIp.getAddress(), serverId);
-      
-      assertEquals(added.getServerId(), serverId);
-
-      removed = api.removeIpFromServerAndRelease(reservedIp.getAddress(), serverId);
-      
-      assertNull(removed.getServerId());
-      assertFalse(removed.isReserved());
-      
-      
-      // reserve an address again!
-      reserveIp();
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerApiExpectTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerApiExpectTest.java
deleted file mode 100644
index ac6c40f..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerApiExpectTest.java
+++ /dev/null
@@ -1,561 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
-import org.jclouds.glesys.domain.Console;
-import org.jclouds.glesys.domain.Cost;
-import org.jclouds.glesys.domain.Ip;
-import org.jclouds.glesys.domain.OSTemplate;
-import org.jclouds.glesys.domain.ResourceStatus;
-import org.jclouds.glesys.domain.ResourceUsage;
-import org.jclouds.glesys.domain.ResourceUsageInfo;
-import org.jclouds.glesys.domain.ResourceUsageValue;
-import org.jclouds.glesys.domain.Server;
-import org.jclouds.glesys.domain.ServerDetails;
-import org.jclouds.glesys.domain.ServerSpec;
-import org.jclouds.glesys.domain.ServerStatus;
-import org.jclouds.glesys.domain.ServerUptime;
-import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
-import org.jclouds.glesys.options.CloneServerOptions;
-import org.jclouds.glesys.options.CreateServerOptions;
-import org.jclouds.glesys.options.DestroyServerOptions;
-import org.jclouds.glesys.options.EditServerOptions;
-import org.jclouds.glesys.options.ServerStatusOptions;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.rest.AuthorizationException;
-import org.jclouds.rest.ResourceNotFoundException;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableSet;
-
-/**
- * Tests annotation parsing of {@code ServerAsyncApi}
- *
- * @author Adrian Cole
- * @author Adam Lowe
- */
-@Test(groups = "unit", testName = "ServerAsyncApiTest")
-public class ServerApiExpectTest extends BaseGleSYSApiExpectTest {
-
-   public void testListServersWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(204).payload(payloadFromResource("/server_list.json")).build()).getServerApi();
-      Server expected = Server.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg").platform("OpenVZ").build();
-
-      assertEquals(api.listServers(), ImmutableSet.<Server>of(expected));
-   }
-
-   public void testListServersWhenReponseIs404IsEmpty() {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/list/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(404).build()).getServerApi();
-
-      assertTrue(api.listServers().isEmpty());
-   }
-
-   public void testGetAllowedArgumentsWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/server/allowedarguments/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(204).payload(payloadFromResource("/server_allowed_arguments.json")).build()).getServerApi();
-
-      Map<String, AllowedArgumentsForCreateServer> expected = new LinkedHashMap<String, AllowedArgumentsForCreateServer>();
-      AllowedArgumentsForCreateServer openvz = AllowedArgumentsForCreateServer.builder()
-            .dataCenters("Amsterdam", "Falkenberg", "New York City", "Stockholm")
-            .memorySizes(128, 256, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288)
-            .diskSizes(5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 150)
-            .cpuCores(1, 2, 3, 4, 5, 6, 7, 8)
-            .templates("Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit", "Debian 5.0 32-bit",
-                  "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11", "Fedora Core 11 64-bit",
-                  "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit", "Slackware 12",
-                  "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit")
-            .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
-            .build();
-      AllowedArgumentsForCreateServer xen = AllowedArgumentsForCreateServer.builder()
-            .memorySizes(512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 14336, 16384)
-            .diskSizes(5, 10, 20, 30, 40, 50, 80, 100, 120, 140, 150, 160, 160, 200, 250, 300)
-            .cpuCores(1, 2, 3, 4, 5, 6, 7, 8)
-            .templates("CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86", "Debian-6 x64",
-                  "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64", "Ubuntu 10.04 LTS 64-bit",
-                  "Ubuntu 10.10 x64", "Ubuntu 11.04 x64", "Windows Server 2008 R2 x64 std",
-                  "Windows Server 2008 R2 x64 web", "Windows Server 2008 x64 web", "Windows Server 2008 x86 web")
-            .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
-            .dataCenters("Falkenberg")
-            .build();
-      expected.put("Xen", xen);
-      expected.put("OpenVZ", openvz);
-      assertEquals(api.getAllowedArgumentsForCreateServerByPlatform(), expected);
-   }
-
-   public void testGetTemplatesWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/server/templates/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_templates.json")).build()).getServerApi();
-
-      ImmutableSet.Builder<OSTemplate> expectedBuilder = ImmutableSet.builder();
-
-      for (String name : new String[]{"Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit",
-            "Debian 5.0 32-bit", "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11",
-            "Fedora Core 11 64-bit", "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit",
-            "Slackware 12", "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit"}) {
-         expectedBuilder.add(OSTemplate.builder().name(name).minDiskSize(5).minMemSize(128).os("linux").platform("OpenVZ").build());
-      }
-
-      for (String name : new String[]{"CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86",
-            "Debian-6 x64", "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64",
-            "Ubuntu 10.04 LTS 64-bit", "Ubuntu 10.10 x64", "Ubuntu 11.04 x64"}) {
-         expectedBuilder.add(OSTemplate.builder().name(name).minDiskSize(5).minMemSize(512)
-               .os(name.startsWith("FreeBSD") ? "freebsd" : "linux").platform("Xen").build());
-      }
-      for (String name : new String[]{"Windows Server 2008 R2 x64 std", "Windows Server 2008 R2 x64 web",
-            "Windows Server 2008 x64 web", "Windows Server 2008 x86 web"}) {
-         expectedBuilder.add(OSTemplate.builder().name(name).minDiskSize(20).minMemSize(1024).os("windows").platform("Xen").build());
-      }
-
-      assertEquals(api.listTemplates(), expectedBuilder.build());
-   }
-
-   public void testGetServerDetailsWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/details/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("includestate", "true")
-                       .addFormParam("serverid", "xm3276891").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerApi();
-
-      ServerDetails actual = api.getServerDetails("xm3276891");
-      assertEquals(actual.toString(), expectedServerDetails().toString());
-   }
-
-   public static ServerDetails expectedServerDetails() {
-      Ip ip = Ip.builder().version4().ip("31.192.231.254").version4().cost(2.0).currency("EUR").build();
-      Cost cost = Cost.builder().amount(10.22).currency("EUR").timePeriod("month").build();
-      return ServerDetails.builder().id("vz1840356").transferGB(50).hostname("test-email-jclouds").cpuCores(1).memorySizeMB(512)
-            .diskSizeGB(5).datacenter("Falkenberg").description("glesys-s-6dd").platform("OpenVZ")
-            .templateName("Ubuntu 10.04 LTS 32-bit").state(Server.State.RUNNING).cost(cost).ips(ip).build();
-   }
-
-   @Test
-   public void testServerDetailsWhenResponseIs4xxReturnsNull() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/details/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("includestate", "true")
-                       .addFormParam("serverid", "xm3276891").build(),
-            HttpResponse.builder().statusCode(404).build()).getServerApi();
-
-      assertNull(api.getServerDetails("xm3276891"));
-   }
-
-   @Test
-   public void testCreateServerWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/create/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("hostname", "jclouds-test")
-                       .addFormParam("rootpassword", "password")
-                       .addFormParam("datacenter", "Falkenberg")
-                       .addFormParam("platform", "OpenVZ")
-                       .addFormParam("templatename", "Ubuntu 32-bit")
-                       .addFormParam("disksize", "5")
-                       .addFormParam("memorysize", "512")
-                       .addFormParam("cpucores", "1")
-                       .addFormParam("transfer", "50").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_noip.json")).build()).getServerApi();
-
-      Cost cost = Cost.builder().amount(6.38).currency("EUR").timePeriod("month").build();
-      ServerDetails expected = ServerDetails.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg").platform("OpenVZ")
-            .templateName("Ubuntu 11.04 64-bit").description("description").cpuCores(1).memorySizeMB(128).diskSizeGB(5).transferGB(50).cost(cost).build();
-
-      assertEquals(
-            api.createServerWithHostnameAndRootPassword(
-                  ServerSpec.builder().datacenter("Falkenberg").platform("OpenVZ").templateName("Ubuntu 32-bit")
-                        .diskSizeGB(5).memorySizeMB(512).cpuCores(1).transferGB(50).build(), "jclouds-test", "password").toString(),
-            expected.toString());
-   }
-
-   public void testCreateServerWithOptsWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/create/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("hostname", "jclouds-test")
-                       .addFormParam("rootpassword", "password")
-                       .addFormParam("datacenter", "Falkenberg")
-                       .addFormParam("platform", "OpenVZ")
-                       .addFormParam("templatename", "Ubuntu 32-bit")
-                       .addFormParam("disksize", "5")
-                       .addFormParam("memorysize", "512")
-                       .addFormParam("cpucores", "1")
-                       .addFormParam("transfer", "50")
-                       .addFormParam("ip", "10.0.0.1")
-                       .addFormParam("description", "Description-of-server").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerApi();
-
-      CreateServerOptions options = CreateServerOptions.Builder.description("Description-of-server").ip("10.0.0.1");
-
-
-      assertEquals(api.createServerWithHostnameAndRootPassword(ServerSpec.builder().datacenter("Falkenberg")
-            .platform("OpenVZ").templateName("Ubuntu 32-bit").diskSizeGB(5).memorySizeMB(512).cpuCores(1).transferGB(50)
-            .build(), "jclouds-test", "password", options), expectedServerDetails());
-   }
-
-   @Test
-   public void testEditServerWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/edit/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "xm3276891")
-                       .addFormParam("description", "this is a different description!")
-                       .addFormParam("hostname", "new-hostname").build(),
-            HttpResponse.builder().statusCode(206).build()).getServerApi();
-
-      api.editServer("xm3276891", EditServerOptions.Builder.description("this is a different description!"),
-            EditServerOptions.Builder.hostname("new-hostname"));
-   }
-
-   @Test
-   public void testEditServerWithOptsWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/edit/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "xm3276891")
-                       .addFormParam("description", "Description-of-server")
-                       .addFormParam("disksize", "1")
-                       .addFormParam("memorysize", "512")
-                       .addFormParam("cpucores", "1")
-                       .addFormParam("hostname", "jclouds-test").build(),
-            HttpResponse.builder().statusCode(200).build()).getServerApi();
-
-      EditServerOptions options =
-            EditServerOptions.Builder.description("Description-of-server").diskSizeGB(1).memorySizeMB(512).cpuCores(1).hostname("jclouds-test");
-
-      api.editServer("xm3276891", options);
-   }
-
-   @Test
-   public void testCloneServerWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/clone/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "xm3276891")
-                       .addFormParam("hostname", "hostname1").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerApi();
-
-      assertEquals(api.cloneServer("xm3276891", "hostname1"), expectedServerDetails());
-   }
-
-   @Test
-   public void testCloneServerWithOptsWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/clone/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "xm3276891")
-                       .addFormParam("hostname", "hostname1")
-                       .addFormParam("description", "Description-of-server")
-                       .addFormParam("disksize", "1")
-                       .addFormParam("memorysize", "512")
-                       .addFormParam("cpucores", "1").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerApi();
-      CloneServerOptions options = (CloneServerOptions) CloneServerOptions.Builder.description("Description-of-server").diskSizeGB(1).memorySizeMB(512).cpuCores(1);
-
-      assertEquals(api.cloneServer("xm3276891", "hostname1", options), expectedServerDetails());
-   }
-
-   @Test(expectedExceptions = {ResourceNotFoundException.class})
-   public void testCloneServerWhenResponseIs4xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/clone/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "xm3276891")
-                       .addFormParam("hostname", "hostname1").build(),
-            HttpResponse.builder().statusCode(404).build()).getServerApi();
-
-      api.cloneServer("xm3276891", "hostname1");
-   }
-
-   public void testGetServerStatusWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/status/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "xm3276891").build(),
-            HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")).build())
-            .getServerApi();
-
-      assertEquals(api.getServerStatus("xm3276891"), expectedServerStatus());
-   }
-
-   public void testGetServerStatusWithOptsWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/status/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server321")
-                       .addFormParam("statustype", "state").build(),
-            HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")).build())
-            .getServerApi();
-
-      assertEquals(api.getServerStatus("server321", ServerStatusOptions.Builder.state()), expectedServerStatus());
-   }
-
-   public void testGetServerStatusWhenResponseIs4xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/status/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server321")
-                       .addFormParam("statustype", "state").build(),
-            HttpResponse.builder().statusCode(404).build())
-            .getServerApi();
-
-      assertNull(api.getServerStatus("server321", ServerStatusOptions.Builder.state()));
-   }
-
-   public void testGetServerLimitsWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/limits/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server321").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_limits.json")).build())
-            .getServerApi();
-
-      api.getServerLimits("server321");
-   }
-
-   public void testGetConsoleWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/console/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server322").build(),
-            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_console.json")).build())
-            .getServerApi();
-
-      Console expected = Console.builder().host("79.99.2.147").port(59478).password("1476897311").protocol("vnc").build();
-
-      assertEquals(api.getConsole("server322"), expected);
-   }
-
-   public void testGetConsoleWhenResponseIs4xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/console/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server322").build(),
-            HttpResponse.builder().statusCode(404).build())
-            .getServerApi();
-
-      assertNull(api.getConsole("server322"));
-   }
-
-   public void testStartServerWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/start/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777").build(),
-            HttpResponse.builder().statusCode(200).build())
-            .getServerApi();
-
-      api.startServer("server777");
-   }
-
-   @Test(expectedExceptions = {AuthorizationException.class})
-   public void testStartServerWhenResponseIs4xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/start/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777").build(),
-            HttpResponse.builder().statusCode(401).build())
-            .getServerApi();
-
-      api.startServer("server777");
-   }
-
-   public void testStopServerWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/stop/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777").build(),
-            HttpResponse.builder().statusCode(200).build())
-            .getServerApi();
-
-      api.stopServer("server777");
-   }
-
-   public void testHardStopServerWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/stop/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("type", "hard")
-                       .addFormParam("serverid", "server777").build(),
-            HttpResponse.builder().statusCode(200).build())
-            .getServerApi();
-
-      api.hardStopServer("server777");
-   }
-
-   @Test(expectedExceptions = {AuthorizationException.class})
-   public void testStopServerWhenResponseIs4xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/stop/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777").build(),
-            HttpResponse.builder().statusCode(401).build())
-            .getServerApi();
-
-      api.stopServer("server777");
-   }
-
-   public void testRebootServerWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/reboot/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777").build(),
-            HttpResponse.builder().statusCode(200).build())
-            .getServerApi();
-
-      api.rebootServer("server777");
-   }
-
-   @Test(expectedExceptions = {AuthorizationException.class})
-   public void testRebootServerWhenResponseIs4xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/reboot/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777").build(),
-            HttpResponse.builder().statusCode(401).build())
-            .getServerApi();
-
-      api.rebootServer("server777");
-   }
-
-   public void testDestroyServerWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/destroy/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777")
-                       .addFormParam("keepip", "true").build(),
-            HttpResponse.builder().statusCode(200).build())
-            .getServerApi();
-
-      api.destroyServer("server777", DestroyServerOptions.Builder.keepIp());
-   }
-
-   @Test(expectedExceptions = {AuthorizationException.class})
-   public void testDestroyServerWhenResponseIs4xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/destroy/format/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777")
-                       .addFormParam("keepip", "false").build(),
-            HttpResponse.builder().statusCode(401).build())
-            .getServerApi();
-
-      api.destroyServer("server777", DestroyServerOptions.Builder.discardIp());
-   }
-
-   public void testResourceUsageWhenResponseIs2xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/resourceusage/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777")
-                       .addFormParam("resolution", "minute")
-                       .addFormParam("resource", "diskioread").build(),
-            HttpResponse.builder().statusCode(200)
-                  .payload(payloadFromResourceWithContentType("/server_resource_usage.json", MediaType.APPLICATION_JSON))
-                  .build())
-            .getServerApi();
-
-      ResourceUsage expected = ResourceUsage.builder().info(
-            ResourceUsageInfo.builder().resolution("minute").resource("diskioread").unit("KB").build())
-            .values(
-                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:21:07+02:00")).build(),
-                  ResourceUsageValue.builder().value(5.1).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:22:05+02:00")).build(),
-                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:23:05+02:00")).build(),
-                  ResourceUsageValue.builder().value(10.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:24:08+02:00")).build(),
-                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:25:12+02:00")).build(),
-                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:26:07+02:00")).build(),
-                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:27:12+02:00")).build(),
-                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:28:05+02:00")).build()
-            ).build();
-      assertEquals(api.getResourceUsage("server777", "diskioread", "minute").toString(), expected.toString());
-   }
-
-   @Test(expectedExceptions = {AuthorizationException.class})
-   public void testResouceUsageWhenResponseIs4xx() throws Exception {
-      ServerApi api = requestSendsResponse(
-            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/resourceusage/format/json")
-                       .addHeader("Accept", "application/json")
-                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
-                       .addFormParam("serverid", "server777")
-                       .addFormParam("resolution", "minute")
-                       .addFormParam("resource", "diskioread").build(),
-            HttpResponse.builder().statusCode(401).build())
-            .getServerApi();
-
-      api.getResourceUsage("server777", "diskioread", "minute");
-   }
-
-   private ServerStatus expectedServerStatus() {
-      ResourceStatus cpu = ResourceStatus.builder().unit("cores").max(1.0).usage(0.0).build();
-      ResourceStatus disk = ResourceStatus.builder().unit("MB").usage(0.0).max(5120).build();
-      ResourceStatus memory = ResourceStatus.builder().unit("MB").usage(2.0).max(512).build();
-      ServerUptime uptime = ServerUptime.builder().current(21).unit("seconds").build();
-      return ServerStatus.builder().state(Server.State.RUNNING).uptime(uptime).
-            cpu(cpu).disk(disk).memory(memory).build();
-   }
-
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerApiLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerApiLiveTest.java
deleted file mode 100644
index f555708..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/features/ServerApiLiveTest.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.features;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
-import org.jclouds.glesys.domain.Console;
-import org.jclouds.glesys.domain.OSTemplate;
-import org.jclouds.glesys.domain.ResourceStatus;
-import org.jclouds.glesys.domain.ResourceUsage;
-import org.jclouds.glesys.domain.Server;
-import org.jclouds.glesys.domain.ServerDetails;
-import org.jclouds.glesys.domain.ServerLimit;
-import org.jclouds.glesys.domain.ServerStatus;
-import org.jclouds.glesys.internal.BaseGleSYSApiWithAServerLiveTest;
-import org.jclouds.glesys.options.CloneServerOptions;
-import org.jclouds.glesys.options.DestroyServerOptions;
-import org.jclouds.glesys.options.EditServerOptions;
-import org.jclouds.glesys.options.ServerStatusOptions;
-import org.jclouds.predicates.RetryablePredicate;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicate;
-
-/**
- * Tests behavior of {@code ServerApi}
- *
- * @author Adrian Cole
- * @author Adam Lowe
- */
-@Test(groups = "live", testName = "ServerApiLiveTest", singleThreaded = true)
-public class ServerApiLiveTest extends BaseGleSYSApiWithAServerLiveTest {
-   public static final String testHostName2 = "jclouds-test2";
-   
-   @BeforeMethod
-   public void setupApi() {
-      api = gleContext.getApi().getServerApi();
-   }
-
-   @AfterGroups(groups = {"live"})
-   public void deleteExtraServer() {
-      if (testServerId2 != null) {
-         api.destroyServer(testServerId2, DestroyServerOptions.Builder.discardIp());
-      }
-   }
-
-   private ServerApi api;
-   private String testServerId2;
-
-   @BeforeMethod
-   public void makeSureServerIsRunning() throws Exception {
-      serverStatusChecker.apply(Server.State.RUNNING);
-   }
-   
-   @Test
-   public void testAllowedArguments() throws Exception {
-      Map<String,AllowedArgumentsForCreateServer> templates = api.getAllowedArgumentsForCreateServerByPlatform();
-      
-      assertTrue(templates.containsKey("OpenVZ"));
-      assertTrue(templates.containsKey("Xen"));
-      
-      checkAllowedArguments(templates.get("OpenVZ"));
-      checkAllowedArguments(templates.get("Xen"));
-   }
-
-   private void checkAllowedArguments(AllowedArgumentsForCreateServer t) {
-      assertNotNull(t);
-
-      assert t.getDataCenters().size() > 0 : t;
-      assert t.getCpuCoreOptions().size() > 0 : t;
-      assert t.getDiskSizesInGB().size() > 0 : t;
-      assert t.getMemorySizesInMB().size() > 0 : t;
-      assert t.getTemplateNames().size() > 0 : t;
-      assert t.getTransfersInGB().size() > 0 : t;
-      assert t.getTransfersInGB().size() > 0 : t;
-   }
-   
-   public void testListTemplates() throws Exception {
-      Set<OSTemplate> oSTemplates = api.listTemplates();
-
-      for(OSTemplate oSTemplate : oSTemplates) {
-         checkTemplate(oSTemplate);
-      }
-   }
-   
-   private void checkTemplate(OSTemplate t) {
-      assertNotNull(t);
-      assertNotNull(t.getName());
-      assertNotNull(t.getOs());
-
-      assertNotNull(t.getPlatform());
-      assert t.getMinDiskSize() > 0 : t;
-      assert t.getMinMemSize() > 0 : t;
-    }
-   
-   public void testListServers() throws Exception {
-      Set<Server> response = api.listServers();
-      assertNotNull(response);
-      assertTrue(response.size() > 0);
-
-      for (Server server : response) {
-         ServerDetails newDetails = api.getServerDetails(server.getId());
-         assertEquals(newDetails.getId(), server.getId());
-         assertEquals(newDetails.getHostname(), server.getHostname());
-         assertEquals(newDetails.getPlatform(), server.getPlatform());
-         assertEquals(newDetails.getDatacenter(), server.getDatacenter());
-         checkServer(newDetails);
-      }
-   }
-
-   public void testServerDetails() throws Exception {
-      ServerDetails details = api.getServerDetails(serverId);
-      checkServer(details);
-      assertEquals("Ubuntu 10.04 LTS 32-bit", details.getTemplateName());
-      assertEquals("Falkenberg", details.getDatacenter());
-      assertEquals("OpenVZ", details.getPlatform());
-      assertEquals(5, details.getDiskSizeGB());
-      assertEquals(512, details.getMemorySizeMB());
-      assertEquals(1, details.getCpuCores());
-      assertEquals(50, details.getTransferGB());
-   }
-
-   public void testServerStatus() throws Exception {
-      ServerStatus newStatus = api.getServerStatus(serverId);
-      checkStatus(newStatus);
-   }
-
-   public void testEditServer() throws Exception {
-      ServerDetails edited = api.editServer(serverId, EditServerOptions.Builder.description("this is a different description!"));
-      assertEquals(edited.getDescription(), "this is a different description!");
-
-      edited = api.editServer(serverId, EditServerOptions.Builder.description("another description!"), EditServerOptions.Builder.hostname("host-name1"));
-      assertEquals(edited.getDescription(), "another description!");
-      assertEquals(edited.getHostname(), "host-name1");
-
-      edited = api.resetPassword(serverId, "anotherpass");
-      assertEquals(edited.getHostname(), "host-name1");
-
-      edited = api.editServer(serverId, EditServerOptions.Builder.hostname(hostName));
-      assertEquals(edited.getHostname(), hostName);
-   }
-
-   @Test
-   public void testRebootServer() throws Exception {
-      assertTrue(serverStatusChecker.apply(Server.State.RUNNING));
-
-      api.rebootServer(serverId);
-      
-      assertTrue(serverStatusChecker.apply(Server.State.RUNNING));
-   }
-
-   @Test
-   public void testStopAndStartServer() throws Exception {
-      assertTrue(serverStatusChecker.apply(Server.State.RUNNING));
-
-      api.stopServer(serverId);
-
-      assertTrue(serverStatusChecker.apply(Server.State.STOPPED));
-
-      api.startServer(serverId);
-
-      assertTrue(serverStatusChecker.apply(Server.State.RUNNING));
-   }
-
-   public void testServerLimits() throws Exception {
-      Map<String, ServerLimit> limits = api.getServerLimits(serverId);
-      assertNotNull(limits);
-      for (Map.Entry<String, ServerLimit> entry : limits.entrySet()) {
-         assertNotNull(entry.getKey());
-         assertNotNull(entry.getValue());
-         ServerLimit limit = entry.getValue();
-         assertTrue(limit.getBarrier() >= 0);
-         assertTrue(limit.getFailCount() == 0);
-         assertTrue(limit.getHeld() >= 0);
-         assertTrue(limit.getLimit() > 0);
-         assertTrue(limit.getMaxHeld() >= 0);
-      }
-   }
-
-   public void testResourceUsage() throws Exception {
-      // test server has only been in existence for less than a minute - check all servers
-      for (Server server : api.listServers()) {
-         ResourceUsage usage = api.getResourceUsage(server.getId(), "diskioread", "minute");
-         assertEquals(usage.getInfo().getResource(), "diskioread");
-         assertEquals(usage.getInfo().getResolution(), "minute");
-
-         usage = api.getResourceUsage(server.getId(), "cpuusage", "minute");
-         assertEquals(usage.getInfo().getResource(), "cpuusage");
-         assertEquals(usage.getInfo().getResolution(), "minute");
-      }
-   }
-
-   public void testConsole() throws Exception {
-      Console console = api.getConsole(serverId);
-      assertNotNull(console);
-      assertNotNull(console.getHost());
-      assertTrue(console.getPort() > 0 && console.getPort() < 65537);
-      assertNotNull(console.getPassword());
-   }
-
-   // takes a few minutes and requires an extra server (used 1 already)
-   @Test(enabled=false)
-   public void testCloneServer() throws Exception {
-      ServerDetails testServer2 = api.cloneServer(serverId, testHostName2, CloneServerOptions.Builder.cpucores(1));
-
-      assertNotNull(testServer2.getId());
-      assertEquals(testServer2.getHostname(), "jclouds-test2");
-      assertTrue(testServer2.getIps().isEmpty());
-      
-      testServerId2 = testServer2.getId();
-
-      RetryablePredicate<Server.State> cloneChecker = new ServerStatusChecker(api, testServerId2, 300, 10, TimeUnit.SECONDS);
-      assertTrue(cloneChecker.apply(Server.State.STOPPED));
-
-      api.startServer(testServer2.getId());
-
-      // TODO ServerStatus==STOPPED suggests the previous call to start should have worked
-      cloneChecker = new RetryablePredicate<Server.State>(
-            new Predicate<Server.State>() {
-
-               public boolean apply(Server.State value) {
-                  ServerStatus status = api.getServerStatus(testServerId2, ServerStatusOptions.Builder.state());
-                  if (status.getState() == value) {
-                     return true;
-                  }
-
-                  api.startServer(testServerId2);
-                  return false;
-               }
-
-            }, 600, 30, TimeUnit.SECONDS);
-
-      assertTrue(cloneChecker.apply(Server.State.RUNNING));
-   }
-
-   private void checkServer(ServerDetails server) {
-      // description can be null
-      assert server.getCpuCores() > 0 : server;
-      assert server.getDiskSizeGB() > 0 : server;
-      assert server.getMemorySizeMB() > 0 : server;
-      assert server.getCost() != null;
-      assert server.getTransferGB() > 0 : server;
-
-      assertNotNull(server.getTemplateName());
-      assertNotNull(server.getIps());
-   }
-
-   private void checkStatus(ServerStatus status) {
-      assertNotNull(status.getState());
-      assertNotNull(status.getUptime());
-
-      
-      for (ResourceStatus usage : new ResourceStatus[] { status.getCpu(), status.getDisk(), status.getMemory() }) {
-         assertNotNull(usage);
-         assert usage.getMax() >= 0.0 : status;
-         assert usage.getUsage() >= 0.0 : status;
-         
-         assertNotNull(usage.getUnit());
-      }
-      
-      assertNotNull(status.getUptime());
-      assert status.getUptime().getCurrent() > 0 : status;
-      assertNotNull(status.getUptime().getUnit());
-   }
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiLiveTest.java
deleted file mode 100644
index 25fedad..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiLiveTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.internal;
-
-import static org.testng.Assert.assertTrue;
-
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
-import org.jclouds.glesys.GleSYSAsyncApi;
-import org.jclouds.glesys.GleSYSApi;
-import org.jclouds.glesys.features.DomainApi;
-import org.jclouds.predicates.RetryablePredicate;
-import org.jclouds.rest.RestContext;
-import org.testng.annotations.BeforeGroups;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicate;
-
-/**
- * Tests behavior of {@code GleSYSApi}
- * 
- * @author Adrian Cole, Adam Lowe
- */
-@Test(groups = "live")
-public class BaseGleSYSApiLiveTest extends BaseComputeServiceContextLiveTest {
-
-   protected RestContext<GleSYSApi, GleSYSAsyncApi> gleContext;
-
-   public BaseGleSYSApiLiveTest() {
-      provider = "glesys";
-   }
-
-   @BeforeGroups(groups = { "integration", "live" })
-   @Override
-   public void setupContext() {
-      super.setupContext();
-      gleContext = view.unwrap();
-   }
-
-   protected void createDomain(String domain) {
-      final DomainApi api = gleContext.getApi().getDomainApi();
-      int before = api.listDomains().size();
-      api.addDomain(domain);
-      RetryablePredicate<Integer> result = new RetryablePredicate<Integer>(new Predicate<Integer>() {
-         public boolean apply(Integer value) {
-            return api.listDomains().size() == value;
-         }
-      }, 30, 1, TimeUnit.SECONDS);
-
-      assertTrue(result.apply(before + 1));
-   }
-
-}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiWithAServerLiveTest.java b/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiWithAServerLiveTest.java
deleted file mode 100644
index 75366af..0000000
--- a/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiWithAServerLiveTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.glesys.internal;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.glesys.domain.Server;
-import org.jclouds.glesys.domain.ServerDetails;
-import org.jclouds.glesys.domain.ServerSpec;
-import org.jclouds.glesys.domain.ServerStatus;
-import org.jclouds.glesys.features.DomainApi;
-import org.jclouds.glesys.features.ServerApi;
-import org.jclouds.glesys.options.DestroyServerOptions;
-import org.jclouds.glesys.options.ServerStatusOptions;
-import org.jclouds.predicates.RetryablePredicate;
-import org.testng.annotations.AfterGroups;
-import org.testng.annotations.BeforeGroups;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Predicate;
-
-/**
- * Tests behavior of {@code GleSYSApi}
- * 
- * @author Adrian Cole, Adam Lowe
- */
-@Test(groups = "live", singleThreaded = true)
-public class BaseGleSYSApiWithAServerLiveTest extends BaseGleSYSApiLiveTest {
-   protected String serverId;
-   protected String hostName = "test-server-jclouds";
-   protected ServerStatusChecker serverStatusChecker;
-
-   public BaseGleSYSApiWithAServerLiveTest() {
-      provider = "glesys";
-   }
-
-   @BeforeGroups(groups = { "integration", "live" })
-   @Override
-   public final void setupContext() {
-      assertNull(serverId, "This method should be called EXACTLY once per run");
-      super.setupContext();
-      serverStatusChecker = createServer(hostName);
-      serverId = serverStatusChecker.getServerId();
-   }
-
-   @AfterGroups(groups = {"integration", "live"})
-   @Override
-   public final void tearDownContext() {
-      gleContext.getApi().getServerApi().destroyServer(serverId, DestroyServerOptions.Builder.discardIp());
-      super.tearDownContext();
-   }
-
-   protected void createDomain(String domain) {
-      final DomainApi api = gleContext.getApi().getDomainApi();
-      int before = api.listDomains().size();
-      api.addDomain(domain);
-      RetryablePredicate<Integer> result = new RetryablePredicate<Integer>(new Predicate<Integer>() {
-         public boolean apply(Integer value) {
-            return api.listDomains().size() == value;
-         }
-      }, 30, 1, TimeUnit.SECONDS);
-
-      assertTrue(result.apply(before + 1));
-   }
-
-   protected ServerStatusChecker createServer(String hostName) {
-      ServerApi api = gleContext.getApi().getServerApi();
-
-      ServerDetails testServer = api.createServerWithHostnameAndRootPassword(
-            ServerSpec.builder().datacenter("Falkenberg").platform("OpenVZ").templateName("Ubuntu 10.04 LTS 32-bit")
-                  .diskSizeGB(5).memorySizeMB(512).cpuCores(1).transferGB(50).build(), hostName, UUID.randomUUID()
-                  .toString().replace("-",""));
-
-      assertNotNull(testServer.getId());
-      assertEquals(testServer.getHostname(), hostName);
-      assertFalse(testServer.getIps().isEmpty());
-
-      ServerStatusChecker runningServerCounter = new ServerStatusChecker(api, testServer.getId(), 180, 10,
-            TimeUnit.SECONDS);
-
-      assertTrue(runningServerCounter.apply(Server.State.RUNNING));
-      return runningServerCounter;
-   }
-
-   public static class ServerStatusChecker extends RetryablePredicate<Server.State> {
-      private final String serverId;
-
-      public String getServerId() {
-         return serverId;
-      }
-
-      public ServerStatusChecker(final ServerApi api, final String serverId, long maxWait, long period,
-            TimeUnit unit) {
-         super(new Predicate<Server.State>() {
-
-            public boolean apply(Server.State value) {
-               ServerStatus status = api.getServerStatus(serverId, ServerStatusOptions.Builder.state());
-               return status.getState() == value;
-            }
-
-         }, maxWait, period, unit);
-         this.serverId = serverId;
-      }
-   }
-}
diff --git a/labs/glesys/src/test/resources/server_details.json b/labs/glesys/src/test/resources/server_details.json
deleted file mode 100644
index 55a79c4..0000000
--- a/labs/glesys/src/test/resources/server_details.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{"response":{"status":{"code":200,"timestamp":"2012-06-21T14:10:57+02:00","text":"OK"},
-    "server":{
-        "serverid":"vz1840356",
-        "hostname":"test-email-jclouds",
-        "description":"glesys-s-6dd",
-        "cpucores":1,
-        "memorysize":512,
-        "disksize":5,
-        "transfer":50,
-        "templatename":"Ubuntu 10.04 LTS 32-bit",
-        "datacenter":"Falkenberg",
-        "managedhosting":"no",
-        "platform":"OpenVZ",
-        "cost":{"amount":10.22,"currency":"EUR","timeperiod":"month"},
-        "iplist":[{"ipaddress":"31.192.231.254","version":4,"cost":2,"currency":"EUR"}],"state":"running"},
-        "debug":{"input":{"includestate":"1","serverid":"vz1840356"}}}}
\ No newline at end of file
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java
index e1a4867..6f0cd99 100644
--- a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApi.java
@@ -23,8 +23,8 @@
 
 import org.jclouds.concurrent.Timeout;
 import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.location.Region;
-import org.jclouds.location.functions.RegionToEndpoint;
+import org.jclouds.location.Zone;
+import org.jclouds.location.functions.ZoneToEndpoint;
 import org.jclouds.openstack.glance.v1_0.features.ImageApi;
 import org.jclouds.openstack.v2_0.features.ExtensionApi;
 import org.jclouds.rest.annotations.Delegate;
@@ -44,23 +44,23 @@
 public interface GlanceApi {
    /**
     * 
-    * @return the Region codes configured
+    * @return the Zone codes configured
     */
    @Provides
-   @Region
-   Set<String> getConfiguredRegions();
+   @Zone
+   Set<String> getConfiguredZones();
 
    /**
     * Provides synchronous access to Extension features.
     */
    @Delegate
-   ExtensionApi getExtensionApiForRegion(
-         @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ExtensionApi getExtensionApiForZone(
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
    /**
     * Provides synchronous access to Image features.
     */
    @Delegate
-   ImageApi getImageApiForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ImageApi getImageApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
 }
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApiMetadata.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApiMetadata.java
index 6669d59..9086048 100644
--- a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApiMetadata.java
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceApiMetadata.java
@@ -28,7 +28,7 @@
 import org.jclouds.openstack.glance.v1_0.config.GlanceRestClientModule;
 import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
 import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
-import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ZoneModule;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.rest.RestContext;
 import org.jclouds.rest.internal.BaseRestApiMetadata;
@@ -86,7 +86,7 @@
          .defaultProperties(GlanceApiMetadata.defaultProperties())
          .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
                                      .add(KeystoneAuthenticationModule.class)
-                                     .add(RegionModule.class)
+                                     .add(ZoneModule.class)
                                      .add(GlanceRestClientModule.class).build());
       }
       
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceAsyncApi.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceAsyncApi.java
index d494d7a..b36ab44 100644
--- a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceAsyncApi.java
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/GlanceAsyncApi.java
@@ -21,8 +21,8 @@
 import java.util.Set;
 
 import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.location.Region;
-import org.jclouds.location.functions.RegionToEndpoint;
+import org.jclouds.location.Zone;
+import org.jclouds.location.functions.ZoneToEndpoint;
 import org.jclouds.openstack.glance.v1_0.features.ImageAsyncApi;
 import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
 import org.jclouds.rest.annotations.Delegate;
@@ -41,23 +41,23 @@
 public interface GlanceAsyncApi {
    /**
     * 
-    * @return the Region codes configured
+    * @return the Zone codes configured
     */
    @Provides
-   @Region
-   Set<String> getConfiguredRegions();
+   @Zone
+   Set<String> getConfiguredZones();
 
    /**
     * Provides asynchronous access to Extension features.
     */
    @Delegate
-   ExtensionAsyncApi getExtensionApiForRegion(
-         @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ExtensionAsyncApi getExtensionApiForZone(
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
    /**
     * Provides asynchronous access to Image features.
     */
    @Delegate
-   ImageAsyncApi getImageApiForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ImageAsyncApi getImageApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
 }
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/config/GlanceRestClientModule.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/config/GlanceRestClientModule.java
index e6d266a..e5bda4a 100644
--- a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/config/GlanceRestClientModule.java
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/config/GlanceRestClientModule.java
@@ -96,7 +96,7 @@
             .build(new CacheLoader<String, Set<? extends Extension>>() {
                @Override
                public Set<? extends Extension> load(String key) throws Exception {
-                  return glanceApi.get().getExtensionApiForRegion(key).listExtensions();
+                  return glanceApi.get().getExtensionApiForZone(key).list();
                }
             });
    }
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/features/ImageApi.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/features/ImageApi.java
index b24e368..0aceab6 100644
--- a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/features/ImageApi.java
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/features/ImageApi.java
@@ -19,9 +19,9 @@
 package org.jclouds.openstack.glance.v1_0.features;
 
 import java.io.InputStream;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.jclouds.collect.PagedIterable;
 import org.jclouds.concurrent.Timeout;
 import org.jclouds.io.Payload;
 import org.jclouds.javax.annotation.Nullable;
@@ -30,6 +30,7 @@
 import org.jclouds.openstack.glance.v1_0.options.CreateImageOptions;
 import org.jclouds.openstack.glance.v1_0.options.ListImageOptions;
 import org.jclouds.openstack.glance.v1_0.options.UpdateImageOptions;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 
 /**
  * Image Services
@@ -41,21 +42,31 @@
  */
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface ImageApi {
-   /**
-    * Returns a set of brief metadata about images
-    */
-   Set<? extends Image> list(ListImageOptions... options);
 
    /**
-    * Returns a set of detailed metadata about images
+    * List all images (IDs, names, links)
+    * 
+    * @return all images (IDs, names, links)
     */
-   Set<? extends ImageDetails> listInDetail(ListImageOptions... options);
+   PagedIterable<? extends Image> list();
+
+   PaginatedCollection<? extends Image> list(ListImageOptions options);
+
+   /**
+    * List all images (all details)
+    * 
+    * @return all images (all details)
+    */
+   PagedIterable<? extends ImageDetails> listInDetail();
+
+   PaginatedCollection<? extends ImageDetails> listInDetail(ListImageOptions options);
+
 
    /**
     * Return metadata about an image with id
     */
    @Nullable
-   ImageDetails show(String id);
+   ImageDetails get(String id);
 
    /**
     * Return image data for image with id
@@ -104,5 +115,5 @@
     *
     * @return true if successful
     */
-   Boolean delete(String id);
+   boolean delete(String id);
 }
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/features/ImageAsyncApi.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/features/ImageAsyncApi.java
index c4b41ca..31c7b5d 100644
--- a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/features/ImageAsyncApi.java
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/features/ImageAsyncApi.java
@@ -19,7 +19,6 @@
 package org.jclouds.openstack.glance.v1_0.features;
 
 import java.io.InputStream;
-import java.util.Set;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
@@ -33,20 +32,26 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
+import org.jclouds.collect.PagedIterable;
 import org.jclouds.io.Payload;
 import org.jclouds.openstack.glance.v1_0.domain.Image;
 import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
 import org.jclouds.openstack.glance.v1_0.functions.ParseImageDetailsFromHeaders;
+import org.jclouds.openstack.glance.v1_0.functions.internal.ParseImageDetails;
+import org.jclouds.openstack.glance.v1_0.functions.internal.ParseImages;
 import org.jclouds.openstack.glance.v1_0.options.CreateImageOptions;
 import org.jclouds.openstack.glance.v1_0.options.ListImageOptions;
 import org.jclouds.openstack.glance.v1_0.options.UpdateImageOptions;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.keystone.v2_0.functions.ReturnEmptyPaginatedCollectionOnNotFoundOr404;
 import org.jclouds.rest.annotations.ExceptionParser;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.functions.ReturnEmptyPagedIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
@@ -65,34 +70,58 @@
 @RequestFilters(AuthenticateRequest.class)
 public interface ImageAsyncApi {
 
+
    /**
-    * @see ImageApi#list
+    * @see ImageApi#list()
     */
    @GET
-   @SelectJson("images")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/images")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Image>> list(ListImageOptions... options);
-   
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseImages.class)
+   @Transform(ParseImages.ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends Image>> list();
+
+   /** @see ImageApi#list(ListImageOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/images")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseImages.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends Image>> list(ListImageOptions options);
+
    /**
-    * @see ImageApi#listInDetail
+    * @see ImageApi#listInDetail()
     */
    @GET
-   @SelectJson("images")
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("/images/detail")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends ImageDetails>> listInDetail(ListImageOptions... options);
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseImageDetails.class)
+   @Transform(ParseImageDetails.ToPagedIterable.class)
+   @ExceptionParser(ReturnEmptyPagedIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends PagedIterable<? extends ImageDetails>> listInDetail();
+
+   /** @see ImageApi#listInDetail(ListImageOptions) */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @Path("/images/detail")
+   @RequestFilters(AuthenticateRequest.class)
+   @ResponseParser(ParseImageDetails.class)
+   @ExceptionParser(ReturnEmptyPaginatedCollectionOnNotFoundOr404.class)
+   ListenableFuture<? extends PaginatedCollection<? extends ImageDetails>> listInDetail(ListImageOptions options);
+
    
    /**
-    * @see ImageApi#show
+    * @see ImageApi#get
     */
    @HEAD
    @Path("/images/{id}")
    @ResponseParser(ParseImageDetailsFromHeaders.class)
    @ExceptionParser(ReturnNullOnNotFoundOr404.class)
-   ListenableFuture<ImageDetails> show(@PathParam("id") String id);
+   ListenableFuture<ImageDetails> get(@PathParam("id") String id);
    
    /**
     * @see ImageApi#getAsStream
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/functions/internal/ParseImageDetails.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/functions/internal/ParseImageDetails.java
new file mode 100644
index 0000000..b111370
--- /dev/null
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/functions/internal/ParseImageDetails.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.glance.v1_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.glance.v1_0.options.ListImageOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.glance.v1_0.GlanceApi;
+import org.jclouds.openstack.glance.v1_0.domain.ImageDetails;
+import org.jclouds.openstack.glance.v1_0.features.ImageApi;
+import org.jclouds.openstack.glance.v1_0.functions.internal.ParseImageDetails.Images;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseImageDetails extends ParseJson<Images<? extends ImageDetails>> {
+   static class Images<T extends ImageDetails> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "images", "images_links" })
+      protected Images(Iterable<T> images, Iterable<Link> images_links) {
+         super(images, images_links);
+      }
+
+   }
+
+   @Inject
+   public ParseImageDetails(Json json) {
+      super(json, new TypeLiteral<Images<? extends ImageDetails>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<ImageDetails, ToPagedIterable> {
+
+      private final GlanceApi api;
+
+      @Inject
+      protected ToPagedIterable(GlanceApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<ImageDetails>> markerToNextForCallingArg0(final String zone) {
+         final ImageApi imageApi = api.getImageApiForZone(zone);
+         return new Function<Object, IterableWithMarker<ImageDetails>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<ImageDetails> apply(Object input) {
+               return IterableWithMarker.class.cast(imageApi.listInDetail(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "listInDetail()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/functions/internal/ParseImages.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/functions/internal/ParseImages.java
new file mode 100644
index 0000000..0b8ea22
--- /dev/null
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/functions/internal/ParseImages.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.openstack.glance.v1_0.functions.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.openstack.glance.v1_0.options.ListImageOptions.Builder.marker;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.CallerArg0ToPagedIterable;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.glance.v1_0.GlanceApi;
+import org.jclouds.openstack.glance.v1_0.domain.Image;
+import org.jclouds.openstack.glance.v1_0.features.ImageApi;
+import org.jclouds.openstack.glance.v1_0.functions.internal.ParseImages.Images;
+import org.jclouds.openstack.keystone.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.inject.TypeLiteral;
+
+/**
+ * boiler plate until we determine a better way
+ * 
+ * @author Adrian Cole
+ */
+@Beta
+@Singleton
+public class ParseImages extends ParseJson<Images<? extends Image>> {
+   static class Images<T extends Image> extends PaginatedCollection<T> {
+
+      @ConstructorProperties({ "images", "images_links" })
+      protected Images(Iterable<T> images, Iterable<Link> images_links) {
+         super(images, images_links);
+      }
+
+   }
+
+   @Inject
+   public ParseImages(Json json) {
+      super(json, new TypeLiteral<Images<? extends Image>>() {
+      });
+   }
+
+   public static class ToPagedIterable extends CallerArg0ToPagedIterable<Image, ToPagedIterable> {
+
+      private final GlanceApi api;
+
+      @Inject
+      protected ToPagedIterable(GlanceApi api) {
+         this.api = checkNotNull(api, "api");
+      }
+
+      @Override
+      protected Function<Object, IterableWithMarker<Image>> markerToNextForCallingArg0(final String zone) {
+         final ImageApi imageApi = api.getImageApiForZone(zone);
+         return new Function<Object, IterableWithMarker<Image>>() {
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public IterableWithMarker<Image> apply(Object input) {
+               return IterableWithMarker.class.cast(imageApi.list(marker(input.toString())));
+            }
+
+            @Override
+            public String toString() {
+               return "list()";
+            }
+         };
+      }
+
+   }
+
+}
diff --git a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/options/ListImageOptions.java b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/options/ListImageOptions.java
index 2df3f43..0328e90 100644
--- a/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/options/ListImageOptions.java
+++ b/labs/openstack-glance/src/main/java/org/jclouds/openstack/glance/v1_0/options/ListImageOptions.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.glance.v1_0.options;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
 import static org.jclouds.openstack.glance.v1_0.options.ImageField.CONTAINER_FORMAT;
 import static org.jclouds.openstack.glance.v1_0.options.ImageField.DISK_FORMAT;
 import static org.jclouds.openstack.glance.v1_0.options.ImageField.IS_PUBLIC;
@@ -31,10 +29,12 @@
 import static org.jclouds.openstack.glance.v1_0.options.ImageField.SIZE_MIN;
 import static org.jclouds.openstack.glance.v1_0.options.ImageField.STATUS;
 
-import org.jclouds.http.options.BaseHttpRequestOptions;
+import java.util.Date;
+
 import org.jclouds.openstack.glance.v1_0.domain.ContainerFormat;
 import org.jclouds.openstack.glance.v1_0.domain.DiskFormat;
 import org.jclouds.openstack.glance.v1_0.domain.Image.Status;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
 
 /**
  * <h2></h2>Usage</h2> The recommended way to instantiate a ListImageOptions object is to statically import
@@ -51,28 +51,10 @@
  * @author Adam Lowe
  * @see <a href="http://glance.openstack.org/glanceapi.html"/>
  */
-public class ListImageOptions extends BaseHttpRequestOptions {
+public class ListImageOptions extends PaginationOptions {
    public static final ListImageOptions NONE = new ListImageOptions();
 
    /**
-    * Given a string value x, return object names greater in value than the specified marker.
-    */
-   public ListImageOptions marker(String marker) {
-      queryParameters.put("marker", checkNotNull(marker, "marker"));
-      return this;
-   }
-
-   /**
-    * For an integer value n, limits the number of results to n values.
-    */
-   public ListImageOptions limit(int limit) {
-      checkState(limit >= 0, "limit must be >= 0");
-      checkState(limit <= 10000, "limit must be <= 10000");
-      queryParameters.put("limit", Integer.toString(limit));
-      return this;
-   }
-
-   /**
     * Return only those images having a matching name attribute
     */
    public ListImageOptions name(String name) {
@@ -267,8 +249,22 @@
        * @see ListImageOptions#marker
        */
       public static ListImageOptions marker(String marker) {
-         ListImageOptions options = new ListImageOptions();
-         return options.marker(marker);
+         return new ListImageOptions().marker(marker);
       }
    }
+
+   @Override
+   public ListImageOptions changesSince(Date ifModifiedSince) {
+      return ListImageOptions.class.cast(super.changesSince(ifModifiedSince));
+   }
+
+   @Override
+   public ListImageOptions marker(String marker) {
+      return ListImageOptions.class.cast(super.marker(marker));
+   }
+
+   @Override
+   public ListImageOptions limit(int limit) {
+      return ListImageOptions.class.cast(super.limit(limit));
+   }
 }
diff --git a/labs/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java b/labs/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java
index a6df24b..6eed0eb 100644
--- a/labs/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java
+++ b/labs/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiExpectTest.java
@@ -64,9 +64,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, list, listResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").list().toString(),
+      assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").list().concat().toString(),
             new ParseImagesTest().expected().toString());
    }
 
@@ -81,7 +81,7 @@
       GlanceApi apiWhenNoExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, list, listResponse);
 
-      assertTrue(apiWhenNoExist.getImageApiForRegion("az-1.region-a.geo-1").list().isEmpty());
+      assertTrue(apiWhenNoExist.getImageApiForZone("az-1.region-a.geo-1").list().concat().isEmpty());
    }
 
    public void testListInDetailWhenResponseIs2xx() throws Exception {
@@ -97,9 +97,9 @@
       GlanceApi apiWhenExistInDetail = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, listInDetail, listInDetailResponse);
 
-      assertEquals(apiWhenExistInDetail.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExistInDetail.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExistInDetail.getImageApiForRegion("az-1.region-a.geo-1").listInDetail().toString(),
+      assertEquals(apiWhenExistInDetail.getImageApiForZone("az-1.region-a.geo-1").listInDetail().concat().toString(),
             new ParseImagesInDetailTest().expected().toString());
    }
 
@@ -115,7 +115,7 @@
       GlanceApi apiWhenNoExistInDetail = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, listInDetail, listInDetailResponse);
 
-      assertTrue(apiWhenNoExistInDetail.getImageApiForRegion("az-1.region-a.geo-1").listInDetail().isEmpty());
+      assertTrue(apiWhenNoExistInDetail.getImageApiForZone("az-1.region-a.geo-1").listInDetail().concat().isEmpty());
    }
 
    public void testShowWhenResponseIs2xx() throws Exception {
@@ -131,9 +131,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, show, showResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").show("fcc451d0-f6e4-4824-ad8f-70ec12326d07").toString(),
+      assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").get("fcc451d0-f6e4-4824-ad8f-70ec12326d07").toString(),
             new ParseImageDetailsFromHeadersTest().expected().toString());
    }
 
@@ -148,7 +148,7 @@
       GlanceApi apiWhenNoExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, show, showResponse);
 
-      assertNull(apiWhenNoExist.getImageApiForRegion("az-1.region-a.geo-1").show("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
+      assertNull(apiWhenNoExist.getImageApiForZone("az-1.region-a.geo-1").get("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
    }
    
 
@@ -163,9 +163,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, getResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(Strings2.toStringAndClose(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").getAsStream("fcc451d0-f6e4-4824-ad8f-70ec12326d07")),
+      assertEquals(Strings2.toStringAndClose(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").getAsStream("fcc451d0-f6e4-4824-ad8f-70ec12326d07")),
                "foo");
    }
 
@@ -180,7 +180,7 @@
       GlanceApi apiWhenNoExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, getResponse);
 
-      assertNull(apiWhenNoExist.getImageApiForRegion("az-1.region-a.geo-1").getAsStream("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
+      assertNull(apiWhenNoExist.getImageApiForZone("az-1.region-a.geo-1").getAsStream("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
    }
 
    public void testCreateWhenResponseIs2xx() throws Exception {
@@ -197,9 +197,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, createResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").create("test", new StringPayload("somedata")),
+      assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").create("test", new StringPayload("somedata")),
             new ParseImageDetailsTest().expected());
    }
 
@@ -218,9 +218,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, createResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").create("test", new StringPayload("somedata"));
+      apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").create("test", new StringPayload("somedata"));
    }
 
    public void testReserveWhenResponseIs2xx() throws Exception {
@@ -236,9 +236,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, createResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").reserve("test"), new ParseImageDetailsTest().expected());
+      assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").reserve("test"), new ParseImageDetailsTest().expected());
    }
 
    @Test(expectedExceptions = AuthorizationException.class)
@@ -255,9 +255,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, createResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").reserve("test");
+      apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").reserve("test");
    }
    
    public void testUpdateMetadataWhenResponseIs2xx() throws Exception {
@@ -282,9 +282,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, updateResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1")
+      assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1")
             .update("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
                   UpdateImageOptions.Builder.name("newname"),
                   UpdateImageOptions.Builder.isPublic(true),
@@ -313,9 +313,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, updateResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1")
+      apiWhenExist.getImageApiForZone("az-1.region-a.geo-1")
             .update("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
                   UpdateImageOptions.Builder.name("newname"),
                   UpdateImageOptions.Builder.isPublic(true));
@@ -336,9 +336,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, updateResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
+      assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
             new StringPayload("somenewdata")), new ParseImageDetailsTest().expected());
    }
 
@@ -360,9 +360,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, updateResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertEquals(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
+      assertEquals(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
             new StringPayload("somenewdata"), UpdateImageOptions.Builder.name("anothernewname")), new ParseImageDetailsTest().expected());
    }
 
@@ -383,9 +383,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, updateResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
+      apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").upload("fcc451d0-f6e4-4824-ad8f-70ec12326d07",
             new StringPayload("somenewdata"), UpdateImageOptions.Builder.name("anothernewname"));
    }
 
@@ -399,9 +399,9 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, getResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertTrue(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").delete("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
+      assertTrue(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").delete("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
    }
 
    public void testDeleteWhenResponseIs4xx() throws Exception {
@@ -415,8 +415,8 @@
       GlanceApi apiWhenExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
             responseWithKeystoneAccess, get, getResponse);
 
-      assertEquals(apiWhenExist.getConfiguredRegions(), ImmutableSet.of("az-1.region-a.geo-1"));
+      assertEquals(apiWhenExist.getConfiguredZones(), ImmutableSet.of("az-1.region-a.geo-1"));
 
-      assertFalse(apiWhenExist.getImageApiForRegion("az-1.region-a.geo-1").delete("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
+      assertFalse(apiWhenExist.getImageApiForZone("az-1.region-a.geo-1").delete("fcc451d0-f6e4-4824-ad8f-70ec12326d07"));
    }
 }
diff --git a/labs/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiLiveTest.java b/labs/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiLiveTest.java
index ef45754..765cc52 100644
--- a/labs/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiLiveTest.java
+++ b/labs/openstack-glance/src/test/java/org/jclouds/openstack/glance/v1_0/features/ImageApiLiveTest.java
@@ -47,9 +47,9 @@
 
    @Test
    public void testList() throws Exception {
-      for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
-         ImageApi api = glanceContext.getApi().getImageApiForRegion(zoneId);
-         Set<? extends Image> response = api.list(ListImageOptions.Builder.limit(100));
+      for (String zoneId : glanceContext.getApi().getConfiguredZones()) {
+         ImageApi api = glanceContext.getApi().getImageApiForZone(zoneId);
+         Set<? extends Image> response = api.list().concat().toImmutableSet();
          assert null != response;
          for (Image image : response) {
             checkImage(image);
@@ -65,13 +65,13 @@
 
    @Test
    public void testListInDetail() throws Exception {
-      for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
-         ImageApi api = glanceContext.getApi().getImageApiForRegion(zoneId);
-         Set<? extends ImageDetails> response = api.listInDetail();
+      for (String zoneId : glanceContext.getApi().getConfiguredZones()) {
+         ImageApi api = glanceContext.getApi().getImageApiForZone(zoneId);
+         Set<? extends ImageDetails> response = api.listInDetail().concat().toImmutableSet();
          assert null != response;
          for (ImageDetails image : response) {
             checkImage(image);
-            ImageDetails newDetails = api.show(image.getId());
+            ImageDetails newDetails = api.get(image.getId());
             checkImageDetails(newDetails);
             checkImageDetailsEqual(image, newDetails);
          }
@@ -93,8 +93,8 @@
    @Test
    public void testCreateUpdateAndDeleteImage() {
       StringPayload imageData = new StringPayload("This isn't really an image!");
-      for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
-         ImageApi api = glanceContext.getApi().getImageApiForRegion(zoneId);
+      for (String zoneId : glanceContext.getApi().getConfiguredZones()) {
+         ImageApi api = glanceContext.getApi().getImageApiForZone(zoneId);
          ImageDetails details = api.create("jclouds-live-test", imageData, diskFormat(DiskFormat.RAW), containerFormat(ContainerFormat.BARE));
          assertEquals(details.getName(), "jclouds-live-test");
          assertEquals(details.getSize().get().longValue(), imageData.getRawContent().length());
@@ -103,7 +103,9 @@
          assertEquals(details.getName(), "jclouds-live-test2");
          assertEquals(details.getMinDisk(), 10);
          
-         Image fromListing = Iterables.getOnlyElement(api.list(ListImageOptions.Builder.name("jclouds-live-test2"), ListImageOptions.Builder.limit(2), ListImageOptions.Builder.containerFormat(ContainerFormat.BARE)));
+         Image fromListing = api.list(
+                  ListImageOptions.Builder.containerFormat(ContainerFormat.BARE).name("jclouds-live-test2").limit(2))
+                  .get(0);
          assertEquals(fromListing.getId(), details.getId());
          assertEquals(fromListing.getSize(), details.getSize());
 
@@ -118,8 +120,8 @@
    @Test
    public void testReserveUploadAndDeleteImage() {
       StringPayload imageData = new StringPayload("This isn't an image!");
-      for (String zoneId : glanceContext.getApi().getConfiguredRegions()) {
-         ImageApi api = glanceContext.getApi().getImageApiForRegion(zoneId);
+      for (String zoneId : glanceContext.getApi().getConfiguredZones()) {
+         ImageApi api = glanceContext.getApi().getImageApiForZone(zoneId);
          ImageDetails details = api.reserve("jclouds-live-res-test", diskFormat(DiskFormat.RAW), containerFormat(ContainerFormat.BARE));
          assertEquals(details.getName(), "jclouds-live-res-test");
  
@@ -128,7 +130,7 @@
          assertEquals(details.getSize().get().longValue(), imageData.getRawContent().length());
          assertEquals(details.getMinDisk(), 10);
 
-         Image fromListing = Iterables.getOnlyElement(api.list(ListImageOptions.Builder.name("jclouds-live-res-test2"), ListImageOptions.Builder.limit(2), ListImageOptions.Builder.containerFormat(ContainerFormat.BARE)));
+         Image fromListing = Iterables.getOnlyElement(api.list(ListImageOptions.Builder.name("jclouds-live-res-test2").limit(2).containerFormat(ContainerFormat.BARE)));
          assertEquals(fromListing.getId(), details.getId());
          assertEquals(fromListing.getSize(), details.getSize());
 
diff --git a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumApi.java b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumApi.java
index 2f9a5ed..b2b24ee 100644
--- a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumApi.java
+++ b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumApi.java
@@ -26,8 +26,7 @@
 
 import org.jclouds.concurrent.Timeout;
 import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.location.Region;
-import org.jclouds.location.functions.RegionToEndpoint;
+import org.jclouds.location.Zone;
 import org.jclouds.location.functions.ZoneToEndpoint;
 import org.jclouds.openstack.quantum.v1_0.features.NetworkApi;
 import org.jclouds.openstack.quantum.v1_0.features.PortApi;
@@ -48,30 +47,30 @@
 @Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
 public interface QuantumApi {
    /**
-    * @return the Region codes configured
+    * @return the Zone codes configured
     */
    @Provides
-   @Region
-   Set<String> getConfiguredRegions();
+   @Zone
+   Set<String> getConfiguredZones();
 
    /**
     * Provides synchronous access to Extension features.
     */
    @Delegate
-   ExtensionApi getExtensionApiForRegion(
-         @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ExtensionApi getExtensionApiForZone(
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
    /**
     * Provides synchronous access to Network features.
     */
    @Delegate
-   NetworkApi getNetworkApiForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   NetworkApi getNetworkApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
    /**
     * Provides synchronous access to Port features.
     */
    @Delegate
    @Path("/networks/{net}")
-   PortApi getPortApiForRegionAndNetwork(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region,
+   PortApi getPortApiForZoneAndNetwork(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone,
                                                @PathParam("net") String networkId);
 }
diff --git a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumApiMetadata.java b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumApiMetadata.java
index 9d38d93..9e986d7 100644
--- a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumApiMetadata.java
+++ b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumApiMetadata.java
@@ -27,7 +27,7 @@
 import org.jclouds.apis.ApiMetadata;
 import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
 import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
-import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
+import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.ZoneModule;
 import org.jclouds.openstack.quantum.v1_0.config.QuantumRestClientModule;
 import org.jclouds.openstack.v2_0.ServiceType;
 import org.jclouds.rest.RestContext;
@@ -85,7 +85,7 @@
          .defaultProperties(QuantumApiMetadata.defaultProperties())
          .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
                                      .add(KeystoneAuthenticationModule.class)
-                                     .add(RegionModule.class)
+                                     .add(ZoneModule.class)
                                      .add(QuantumRestClientModule.class).build());
       }
       
diff --git a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumAsyncApi.java b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumAsyncApi.java
index 0ea08a3..4a6ccd8 100644
--- a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumAsyncApi.java
+++ b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/QuantumAsyncApi.java
@@ -24,8 +24,8 @@
 import javax.ws.rs.PathParam;
 
 import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.location.Region;
-import org.jclouds.location.functions.RegionToEndpoint;
+import org.jclouds.location.Zone;
+import org.jclouds.location.functions.ZoneToEndpoint;
 import org.jclouds.openstack.quantum.v1_0.features.NetworkAsyncApi;
 import org.jclouds.openstack.quantum.v1_0.features.PortAsyncApi;
 import org.jclouds.openstack.v2_0.features.ExtensionAsyncApi;
@@ -45,30 +45,30 @@
 public interface QuantumAsyncApi {
    /**
     * 
-    * @return the Region codes configured
+    * @return the Zone codes configured
     */
    @Provides
-   @Region
-   Set<String> getConfiguredRegions();
+   @Zone
+   Set<String> getConfiguredZones();
 
    /**
     * Provides asynchronous access to Extension features.
     */
    @Delegate
-   ExtensionAsyncApi getExtensionApiForRegion(
-         @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   ExtensionAsyncApi getExtensionApiForZone(
+         @EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
    /**
     * Provides asynchronous access to Network features.
     */
    @Delegate
-   NetworkAsyncApi getNetworkApiForRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region);
+   NetworkAsyncApi getNetworkApiForZone(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone);
 
    /**
     * Provides asynchronous access to Port features.
     */
    @Delegate
    @Path("/networks/{net}")
-   PortAsyncApi getPortApiForRegionAndNetwork(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region,
+   PortAsyncApi getPortApiForZoneAndNetwork(@EndpointParam(parser = ZoneToEndpoint.class) @Nullable String zone,
                                                     @PathParam("net") String networkId);
 }
diff --git a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/config/QuantumRestClientModule.java b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/config/QuantumRestClientModule.java
index 4b7be5b..4290fa1 100644
--- a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/config/QuantumRestClientModule.java
+++ b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/config/QuantumRestClientModule.java
@@ -70,6 +70,7 @@
          .put(PortApi.class, PortAsyncApi.class)
          .build();
 
+   @SuppressWarnings("unchecked")
    public QuantumRestClientModule() {
       super(TypeToken.class.cast(TypeToken.of(QuantumApi.class)), TypeToken.class.cast(TypeToken.of(QuantumAsyncApi.class)), DELEGATE_MAP);
    }
@@ -99,7 +100,7 @@
             .build(new CacheLoader<String, Set<? extends Extension>>() {
                @Override
                public Set<? extends Extension> load(String key) throws Exception {
-                  return quantumApi.get().getExtensionApiForRegion(key).listExtensions();
+                  return quantumApi.get().getExtensionApiForZone(key).list();
                }
             });
    }
diff --git a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApi.java b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApi.java
index 116a23e..7951182 100644
--- a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApi.java
+++ b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.openstack.quantum.v1_0.features;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -26,6 +25,8 @@
 import org.jclouds.openstack.quantum.v1_0.domain.NetworkDetails;
 import org.jclouds.openstack.quantum.v1_0.domain.Reference;
 
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides synchronous access to Network operations on the openstack quantum API.
  * <p/>
@@ -44,12 +45,12 @@
     * Returns the list of all networks currently defined in Quantum for the current tenant. The list provides the unique
     * identifier of each network configured for the tenant.
     */
-   Set<? extends Reference> listReferences();
+   FluentIterable<? extends Reference> listReferences();
 
    /**
     * Returns all networks currently defined in Quantum for the current tenant.
     */
-   Set<? extends Network> list();
+   FluentIterable<? extends Network> list();
 
    /**
     * Returns the specific network.
diff --git a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/NetworkAsyncApi.java b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/NetworkAsyncApi.java
index ffb6805..64687a5 100644
--- a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/NetworkAsyncApi.java
+++ b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/NetworkAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.quantum.v1_0.features;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -40,9 +38,10 @@
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
 import org.jclouds.rest.annotations.WrapWith;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -63,8 +62,8 @@
     */
    @GET
    @SelectJson("networks")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Reference>> listReferences();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends Reference>> listReferences();
 
    /**
     * @see NetworkApi#list
@@ -72,8 +71,8 @@
    @GET
    @SelectJson("networks")
    @Path("/detail")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Network>> list();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends Network>> list();
 
    /**
     * @see NetworkApi#get
diff --git a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/PortApi.java b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/PortApi.java
index 5f65506..b4a1680 100644
--- a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/PortApi.java
+++ b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/PortApi.java
@@ -18,7 +18,6 @@
  */
 package org.jclouds.openstack.quantum.v1_0.features;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
@@ -27,6 +26,8 @@
 import org.jclouds.openstack.quantum.v1_0.domain.PortDetails;
 import org.jclouds.openstack.quantum.v1_0.domain.Reference;
 
+import com.google.common.collect.FluentIterable;
+
 /**
  * Provides synchronous access to Port operations on the openstack quantum API.
  * <p/>
@@ -44,12 +45,12 @@
    /**
     * Returns the list of all ports currently defined in Quantum for the requested network
     */
-   Set<? extends Reference> listReferences();
+   FluentIterable<? extends Reference> listReferences();
 
    /**
     * Returns the set of ports currently defined in Quantum for the requested network.
     */
-   Set<? extends Port> list();
+   FluentIterable<? extends Port> list();
 
    /**
     * Returns a specific port.
diff --git a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/PortAsyncApi.java b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/PortAsyncApi.java
index a11b474..fccae57 100644
--- a/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/PortAsyncApi.java
+++ b/labs/openstack-quantum/src/main/java/org/jclouds/openstack/quantum/v1_0/features/PortAsyncApi.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.openstack.quantum.v1_0.features;
 
-import java.util.Set;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -40,9 +38,10 @@
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.annotations.SkipEncoding;
 import org.jclouds.rest.annotations.WrapWith;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
 import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
 
+import com.google.common.collect.FluentIterable;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -63,8 +62,8 @@
     */
    @GET
    @SelectJson("ports")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Reference>> listReferences();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends Reference>> listReferences();
 
    /**
     * @see PortApi#list
@@ -72,8 +71,8 @@
    @GET
    @SelectJson("ports")
    @Path("/detail")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   ListenableFuture<? extends Set<? extends Port>> list();
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<? extends FluentIterable<? extends Port>> list();
 
    /**
     * @see PortApi#get
diff --git a/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApiExpectTest.java b/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApiExpectTest.java
index bf23dfb..16190fa 100644
--- a/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApiExpectTest.java
+++ b/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApiExpectTest.java
@@ -53,9 +53,9 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/list_network_refs.json", APPLICATION_JSON)).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
       
-      Set<? extends Reference> nets = api.listReferences();
+      Set<? extends Reference> nets = api.listReferences().toImmutableSet();
       assertEquals(nets, listOfNetworkRefs());
    }
 
@@ -64,7 +64,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       assertTrue(api.listReferences().isEmpty());
    }
@@ -74,9 +74,9 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/detail").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/list_networks.json", APPLICATION_JSON)).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
-      Set<? extends Network> nets = api.list();
+      Set<? extends Network> nets = api.list().toImmutableSet();
       assertEquals(nets, listOfNetworks());
    }
 
@@ -85,7 +85,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/detail").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       assertTrue(api.list().isEmpty());
    }
@@ -95,7 +95,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/network.json", APPLICATION_JSON)).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       Network net = api.get("16dba3bc-f3fa-4775-afdc-237e12c72f6a");
       assertEquals(net, new ParseNetworkTest().expected());
@@ -106,7 +106,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       assertNull(api.get("16dba3bc-f3fa-4775-afdc-237e12c72f6a"));
    }
@@ -116,7 +116,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/detail").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/network_details.json", APPLICATION_JSON)).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       NetworkDetails net = api.getDetails("16dba3bc-f3fa-4775-afdc-237e12c72f6a");
       assertEquals(net, new ParseNetworkDetailsTest().expected());
@@ -127,7 +127,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/detail").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       assertNull(api.getDetails("16dba3bc-f3fa-4775-afdc-237e12c72f6a"));
    }
@@ -138,7 +138,7 @@
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks").method("POST")
                   .payload(payloadFromStringWithContentType("{\"network\":{\"name\":\"another-test\"}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromStringWithContentType("{\"network\":{\"id\":\"12345\"}}", APPLICATION_JSON)).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       Reference net = api.create("another-test");
       assertEquals(net, Reference.builder().id("12345").build());
@@ -151,7 +151,7 @@
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks").method("POST")
                   .payload(payloadFromStringWithContentType("{\"network\":{\"name\":\"another-test\"}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(401).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       api.create("another-test");
    }
@@ -162,7 +162,7 @@
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/12345").method("PUT")
                   .payload(payloadFromStringWithContentType("{\"network\":{\"name\":\"another-test\"}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(200).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       assertTrue(api.rename("12345", "another-test"));
    }
@@ -174,7 +174,7 @@
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/12345").method("PUT")
                   .payload(payloadFromStringWithContentType("{\"network\":{\"name\":\"another-test\"}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(404).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       api.rename("12345", "another-test");
    }
@@ -184,7 +184,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/12345").method("DELETE").build(),
             HttpResponse.builder().statusCode(200).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       assertTrue(api.delete("12345"));
    }
@@ -195,7 +195,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/12345").method("DELETE").build(),
             HttpResponse.builder().statusCode(403).build())
-            .getNetworkApiForRegion("region-a.geo-1");
+            .getNetworkApiForZone("region-a.geo-1");
 
       api.delete("12345");
    }
diff --git a/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApiLiveTest.java b/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApiLiveTest.java
index 5add5bf..6f5cdb1 100644
--- a/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApiLiveTest.java
+++ b/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/NetworkApiLiveTest.java
@@ -41,9 +41,9 @@
 public class NetworkApiLiveTest extends BaseQuantumApiLiveTest {
 
    public void testListNetworks() {
-      for (String regionId : quantumContext.getApi().getConfiguredRegions()) {
-         Set<? extends Reference> ids = quantumContext.getApi().getNetworkApiForRegion(regionId).listReferences();
-         Set<? extends Network> networks = quantumContext.getApi().getNetworkApiForRegion(regionId).list();
+      for (String zoneId : quantumContext.getApi().getConfiguredZones()) {
+         Set<? extends Reference> ids = quantumContext.getApi().getNetworkApiForZone(zoneId).listReferences().toImmutableSet();
+         Set<? extends Network> networks = quantumContext.getApi().getNetworkApiForZone(zoneId).list().toImmutableSet();
          assertNotNull(ids);
          assertEquals(ids.size(), networks.size());
          for (Network network : networks) {
@@ -54,8 +54,8 @@
    }
 
    public void testCreateUpdateAndDeleteNetwork() {
-      for (String regionId : quantumContext.getApi().getConfiguredRegions()) {
-         NetworkApi api = quantumContext.getApi().getNetworkApiForRegion(regionId);
+      for (String zoneId : quantumContext.getApi().getConfiguredZones()) {
+         NetworkApi api = quantumContext.getApi().getNetworkApiForZone(zoneId);
          Reference net = api.create("jclouds-test");
          assertNotNull(net);
 
diff --git a/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/PortApiExpectTest.java b/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/PortApiExpectTest.java
index 02a61a1..47764d3 100644
--- a/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/PortApiExpectTest.java
+++ b/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/PortApiExpectTest.java
@@ -54,9 +54,9 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/1a104cf5-cb18-4d35-9407-2fd2646d9d0b/ports").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromStringWithContentType("{\"ports\": [{\"id\": \"a6058a59-fa8c-46cc-bac8-08904e6ff0a5\"}]}", APPLICATION_JSON)).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "1a104cf5-cb18-4d35-9407-2fd2646d9d0b");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "1a104cf5-cb18-4d35-9407-2fd2646d9d0b");
 
-      Set<? extends Reference> nets = api.listReferences();
+      Set<? extends Reference> nets = api.listReferences().toImmutableSet();
       assertEquals(nets, ImmutableSet.of(Reference.builder().id("a6058a59-fa8c-46cc-bac8-08904e6ff0a5").build()));
    }
 
@@ -65,7 +65,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/1a104cf5-cb18-4d35-9407-2fd2646d9d0b/ports").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "1a104cf5-cb18-4d35-9407-2fd2646d9d0b");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "1a104cf5-cb18-4d35-9407-2fd2646d9d0b");
 
       assertTrue(api.listReferences().isEmpty());
    }
@@ -75,9 +75,9 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/1a104cf5-cb18-4d35-9407-2fd2646d9d0b/ports/detail").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromStringWithContentType("{\"ports\": [{\"state\": \"DOWN\", \"id\": \"814ae4bb-33d9-425f-8ee2-13a5c90b1465\"}]}", APPLICATION_JSON)).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "1a104cf5-cb18-4d35-9407-2fd2646d9d0b");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "1a104cf5-cb18-4d35-9407-2fd2646d9d0b");
 
-      Set<? extends Port> nets = api.list();
+      Set<? extends Port> nets = api.list().toImmutableSet();
       assertEquals(nets, ImmutableSet.of(Port.builder().state(Port.State.DOWN).id("814ae4bb-33d9-425f-8ee2-13a5c90b1465").build()));
    }
 
@@ -86,7 +86,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/1a104cf5-cb18-4d35-9407-2fd2646d9d0b/ports/detail").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "1a104cf5-cb18-4d35-9407-2fd2646d9d0b");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "1a104cf5-cb18-4d35-9407-2fd2646d9d0b");
 
       assertTrue(api.list().isEmpty());
    }
@@ -96,7 +96,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/646c123b-871a-4124-9fa2-a94f04a582df").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/port.json", APPLICATION_JSON)).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       Port port = api.get("646c123b-871a-4124-9fa2-a94f04a582df");
       assertEquals(port, new ParsePortTest().expected());
@@ -107,7 +107,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/646c123b-871a-4124-9fa2-a94f04a582df").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       assertNull(api.get("646c123b-871a-4124-9fa2-a94f04a582df"));
    }
@@ -117,7 +117,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/646c123b-871a-4124-9fa2-a94f04a582df/detail").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/port_details.json", APPLICATION_JSON)).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       PortDetails net = api.getDetails("646c123b-871a-4124-9fa2-a94f04a582df");
       assertEquals(net, new ParsePortDetailsTest().expected());
@@ -128,7 +128,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/646c123b-871a-4124-9fa2-a94f04a582df/detail").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       assertNull(api.getDetails("646c123b-871a-4124-9fa2-a94f04a582df"));
    }
@@ -138,7 +138,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports").method("POST").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromStringWithContentType("{\"port\":{\"id\":\"12345\"}}", APPLICATION_JSON)).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       Reference port = api.create();
       assertEquals(port, Reference.builder().id("12345").build());
@@ -150,7 +150,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports").method("POST").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       api.create();
    }
@@ -161,7 +161,7 @@
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/77777").method("PUT")
                   .payload(payloadFromStringWithContentType("{\"port\":{\"state\":\"ACTIVE\"}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(200).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       assertTrue(api.updateState("77777", Port.State.ACTIVE));
    }
@@ -173,7 +173,7 @@
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/77777").method("PUT")
                   .payload(payloadFromStringWithContentType("{\"port\":{\"state\":\"ACTIVE\"}}", MediaType.APPLICATION_JSON)).build(),
             HttpResponse.builder().statusCode(401).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       api.updateState("77777", Port.State.ACTIVE);
    }
@@ -183,7 +183,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/77777/attachment").build(),
             HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/attachment.json", APPLICATION_JSON)).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       Attachment attachment = api.showAttachment("77777");
       assertEquals(attachment, Attachment.builder().id("jclouds-live-test").build());
@@ -194,7 +194,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/77777/attachment").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       assertNull(api.showAttachment("77777"));
    }
@@ -206,7 +206,7 @@
             .payload(payloadFromStringWithContentType("{\"attachment\":{\"id\":\"jclouds-live-test\"}}", MediaType.APPLICATION_JSON))
                   .method("PUT").build(),
             HttpResponse.builder().statusCode(200).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       assertTrue(api.plugAttachment("77777", "jclouds-live-test"));
    }
@@ -219,7 +219,7 @@
                   .payload(payloadFromStringWithContentType("{\"attachment\":{\"id\":\"jclouds-live-test\"}}", MediaType.APPLICATION_JSON))
                   .method("PUT").build(),
             HttpResponse.builder().statusCode(403).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       api.plugAttachment("77777", "jclouds-live-test");
    }
@@ -228,7 +228,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/77777/attachment").method("DELETE").build(),
             HttpResponse.builder().statusCode(200).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       assertTrue(api.unplugAttachment("77777"));
    }
@@ -239,7 +239,7 @@
             keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess,
             authenticatedGET().endpoint(endpoint + "/tenants/3456/networks/16dba3bc-f3fa-4775-afdc-237e12c72f6a/ports/77777/attachment").method("DELETE").build(),
             HttpResponse.builder().statusCode(404).build())
-            .getPortApiForRegionAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
+            .getPortApiForZoneAndNetwork("region-a.geo-1", "16dba3bc-f3fa-4775-afdc-237e12c72f6a");
 
       api.unplugAttachment("77777");
    }
diff --git a/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/PortApiLiveTest.java b/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/PortApiLiveTest.java
index b179061..baf37ff 100644
--- a/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/PortApiLiveTest.java
+++ b/labs/openstack-quantum/src/test/java/org/jclouds/openstack/quantum/v1_0/features/PortApiLiveTest.java
@@ -44,13 +44,13 @@
 public class PortApiLiveTest extends BaseQuantumApiLiveTest {
 
    public void testListPorts() {
-      for (String regionId : quantumContext.getApi().getConfiguredRegions()) {
-         NetworkApi netApi = quantumContext.getApi().getNetworkApiForRegion(regionId);
-         Set<? extends Reference> nets = netApi.listReferences();
+      for (String zoneId : quantumContext.getApi().getConfiguredZones()) {
+         NetworkApi netApi = quantumContext.getApi().getNetworkApiForZone(zoneId);
+         Set<? extends Reference> nets = netApi.listReferences().toImmutableSet();
          for(Reference net : nets) {
-            PortApi portApi = quantumContext.getApi().getPortApiForRegionAndNetwork(regionId, net.getId());
-            Set<? extends Reference> portRefs = portApi.listReferences();
-            Set<? extends Port> ports = portApi.list();
+            PortApi portApi = quantumContext.getApi().getPortApiForZoneAndNetwork(zoneId, net.getId());
+            Set<? extends Reference> portRefs = portApi.listReferences().toImmutableSet();
+            Set<? extends Port> ports = portApi.list().toImmutableSet();
             
             assertEquals(portRefs.size(), ports.size());
             for (Port port : ports) {
@@ -61,11 +61,11 @@
    }
 
    public void testCreateUpdateAndDeletePort() {
-      for (String regionId : quantumContext.getApi().getConfiguredRegions()) {
-         NetworkApi netApi = quantumContext.getApi().getNetworkApiForRegion(regionId);
+      for (String zoneId : quantumContext.getApi().getConfiguredZones()) {
+         NetworkApi netApi = quantumContext.getApi().getNetworkApiForZone(zoneId);
          Reference net = netApi.create("jclouds-port-test");
          assertNotNull(net);
-         PortApi portApi = quantumContext.getApi().getPortApiForRegionAndNetwork(regionId, net.getId());
+         PortApi portApi = quantumContext.getApi().getPortApiForZoneAndNetwork(zoneId, net.getId());
 
          Reference portRef = portApi.create();
          assertNotNull(portRef);
@@ -109,12 +109,12 @@
 
    @Test(enabled=false) // assuming attachmentId matters in the wild
    public void testAttachAndDetachPort() {
-      for (String regionId : quantumContext.getApi().getConfiguredRegions()) {
-         NetworkApi netApi = quantumContext.getApi().getNetworkApiForRegion(regionId);
+      for (String zoneId : quantumContext.getApi().getConfiguredZones()) {
+         NetworkApi netApi = quantumContext.getApi().getNetworkApiForZone(zoneId);
          Reference net = netApi.create("jclouds-attach-test");
          assertNotNull(net);
 
-         PortApi portApi = quantumContext.getApi().getPortApiForRegionAndNetwork(regionId, net.getId());
+         PortApi portApi = quantumContext.getApi().getPortApiForZoneAndNetwork(zoneId, net.getId());
 
          Reference port = portApi.create();
          assertNotNull(port);
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftRestClientModule.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftRestClientModule.java
index a0489d0..fe022ae 100644
--- a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftRestClientModule.java
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/config/SwiftRestClientModule.java
@@ -73,6 +73,7 @@
          .put(ObjectApi.class, ObjectAsyncApi.class)
          .build();
 
+   @SuppressWarnings("unchecked")
    public SwiftRestClientModule() {
       super(TypeToken.class.cast(TypeToken.of(SwiftApi.class)), TypeToken.class.cast(TypeToken.of(SwiftAsyncApi.class)), DELEGATE_MAP);
    }
@@ -102,7 +103,7 @@
             .build(new CacheLoader<String, Set<? extends Extension>>() {
                @Override
                public Set<? extends Extension> load(String key) throws Exception {
-                  return swiftApi.get().getExtensionApiForRegion(key).listExtensions();
+                  return swiftApi.get().getExtensionApiForRegion(key).list();
                }
             });
    }
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
new file mode 100644
index 0000000..db42896
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Account.java
@@ -0,0 +1,104 @@
+package org.jclouds.openstack.swift.v1.domain;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+
+import java.beans.ConstructorProperties;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * @author Adrian Cole
+ * @see <a href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-account-metadata.html">api doc</a>
+ */
+public class Account {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromAccountMetadata(this);
+   }
+
+   public static class Builder {
+      protected int containerCount;
+      protected long bytesUsed;
+
+      /**
+       * @see Account#getContainerCount()
+       */
+      public Builder containerCount(int containerCount) {
+         this.containerCount = containerCount;
+         return this;
+      }
+
+      /**
+       * @see Account#getBytesUsed()
+       */
+      public Builder bytesUsed(long bytesUsed) {
+         this.bytesUsed = bytesUsed;
+         return this;
+      }
+
+      public Account build() {
+         return new Account(containerCount, bytesUsed);
+      }
+
+      public Builder fromAccountMetadata(Account from) {
+         return containerCount(from.getContainerCount()).bytesUsed(from.getBytesUsed());
+      }
+   }
+  
+   protected int containerCount;
+   protected long bytesUsed;
+
+   @ConstructorProperties({"containerCount", "bytesUsed"})
+   protected Account(int containerCount, long bytesUsed) {
+      this.containerCount = containerCount;
+      this.bytesUsed = bytesUsed;
+   }
+
+   /**
+    * 
+    * @return the number of containers in OpenStack Object Storage for the account
+    */
+   public int getContainerCount() {
+      return containerCount;
+   }
+
+   /**
+    * @return the total bytes stored in OpenStack Object Storage for the account
+    */
+   public long getBytesUsed() {
+      return bytesUsed;
+   }
+
+   @Override
+   public boolean equals(Object object) {
+      if (this == object) {
+         return true;
+      }
+      if (object instanceof Account) {
+         final Account other = Account.class.cast(object);
+         return equal(getContainerCount(), other.getContainerCount()) && equal(getBytesUsed(), other.getBytesUsed());
+      } else {
+         return false;
+      }
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(getContainerCount(), getBytesUsed());
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   protected ToStringHelper string() {
+      return toStringHelper("").add("containerCount", getContainerCount()).add("bytesUsed", getBytesUsed());
+   }
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/AccountMetadata.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/AccountMetadata.java
deleted file mode 100644
index b3e70da..0000000
--- a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/AccountMetadata.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package org.jclouds.openstack.swift.v1.domain;
-
-import static com.google.common.base.Objects.equal;
-import static com.google.common.base.Objects.toStringHelper;
-
-import java.beans.ConstructorProperties;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * @author Adrian Cole
- * @see <a href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/retrieve-account-metadata.html">api doc</a>
- */
-public class AccountMetadata {
-
-   public static Builder builder() {
-      return new Builder();
-   }
-
-   public Builder toBuilder() {
-      return builder().fromAccountMetadata(this);
-   }
-
-   public static class Builder {
-      protected int containerCount;
-      protected long bytesUsed;
-
-      /**
-       * @see AccountMetadata#getContainerCount()
-       */
-      public Builder containerCount(int containerCount) {
-         this.containerCount = containerCount;
-         return this;
-      }
-
-      /**
-       * @see AccountMetadata#getBytesUsed()
-       */
-      public Builder bytesUsed(long bytesUsed) {
-         this.bytesUsed = bytesUsed;
-         return this;
-      }
-
-      public AccountMetadata build() {
-         return new AccountMetadata(containerCount, bytesUsed);
-      }
-
-      public Builder fromAccountMetadata(AccountMetadata from) {
-         return containerCount(from.getContainerCount()).bytesUsed(from.getBytesUsed());
-      }
-   }
-  
-   protected int containerCount;
-   protected long bytesUsed;
-
-   @ConstructorProperties({"containerCount", "bytesUsed"})
-   protected AccountMetadata(int containerCount, long bytesUsed) {
-      this.containerCount = containerCount;
-      this.bytesUsed = bytesUsed;
-   }
-
-   /**
-    * 
-    * @return the number of containers in OpenStack Object Storage for the account
-    */
-   public int getContainerCount() {
-      return containerCount;
-   }
-
-   /**
-    * @return the total bytes stored in OpenStack Object Storage for the account
-    */
-   public long getBytesUsed() {
-      return bytesUsed;
-   }
-
-   @Override
-   public boolean equals(Object object) {
-      if (this == object) {
-         return true;
-      }
-      if (object instanceof AccountMetadata) {
-         final AccountMetadata other = AccountMetadata.class.cast(object);
-         return equal(getContainerCount(), other.getContainerCount()) && equal(getBytesUsed(), other.getBytesUsed());
-      } else {
-         return false;
-      }
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(getContainerCount(), getBytesUsed());
-   }
-
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-   protected ToStringHelper string() {
-      return toStringHelper("").add("containerCount", getContainerCount()).add("bytesUsed", getBytesUsed());
-   }
-}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
new file mode 100644
index 0000000..ef459e6
--- /dev/null
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/Container.java
@@ -0,0 +1,141 @@
+package org.jclouds.openstack.swift.v1.domain;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * retrieve a list of existing storage containers ordered by name. The sort order for the name is
+ * based on a binary comparison, a single built-in collating sequence that compares string data
+ * using SQLite's memcmp() function, regardless of text encoding.
+ * 
+ * @author Adrian Cole
+ * @see <a
+ *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/s_listcontainers.html">api
+ *      doc</a>
+ */
+public class Container implements Comparable<Container> {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromContainer(this);
+   }
+
+   public static class Builder {
+      protected String name;
+      protected int count;
+      protected int bytes;
+
+      /**
+       * @see Container#getName()
+       */
+      public Builder name(String name) {
+         this.name = checkNotNull(name, "name");
+         return this;
+      }
+
+      /**
+       * @see Container#getCount()
+       */
+      public Builder count(int count) {
+         this.count = count;
+         return this;
+      }
+
+      /**
+       * @see Container#getBytes()
+       */
+      public Builder bytes(int bytes) {
+         this.bytes = bytes;
+         return this;
+      }
+
+      public Container build() {
+         return new Container(name, count, bytes);
+      }
+
+      public Builder fromContainer(Container from) {
+         return name(from.getName()).count(from.getCount()).bytes(from.getBytes());
+      }
+   }
+  
+   protected String name;
+   protected int count;
+   protected int bytes;
+
+   @ConstructorProperties({"name", "count", "bytes"})
+   protected Container(String name, int count, int bytes) {
+      this.name = checkNotNull(name, "name");
+      this.count = count;
+      this.bytes = bytes;
+   }
+
+   /**
+    * 
+    * @return the name of the container
+    */
+   public String getName() {
+      return name;
+   }
+
+   /**
+    * 
+    * @return the number of objects in the container
+    */
+   public int getCount() {
+      return count;
+   }
+
+   /**
+    * @return the total bytes stored in this container
+    */
+   public int getBytes() {
+      return bytes;
+   }
+
+   @Override
+   public boolean equals(Object object) {
+      if (this == object) {
+         return true;
+      }
+      if (object instanceof Container) {
+         final Container other = Container.class.cast(object);
+         return equal(getName(), other.getName()) && equal(getCount(), other.getCount())
+                  && equal(getBytes(), other.getBytes());
+      } else {
+         return false;
+      }
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(getName(), getCount(), getBytes());
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   protected ToStringHelper string() {
+      return toStringHelper("").add("name", getName()).add("count", getCount()).add("bytes", getBytes());
+   }
+
+   @Override
+   public int compareTo(Container that) {
+      if (that == null)
+         return 1;
+      if (this == that)
+         return 0;
+      return this.getName().compareTo(that.getName());
+   }
+
+}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ContainerMetadata.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ContainerMetadata.java
deleted file mode 100644
index 1cbff85..0000000
--- a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/domain/ContainerMetadata.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package org.jclouds.openstack.swift.v1.domain;
-
-import static com.google.common.base.Objects.equal;
-import static com.google.common.base.Objects.toStringHelper;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.beans.ConstructorProperties;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * retrieve a list of existing storage containers ordered by name. The sort order for the name is
- * based on a binary comparison, a single built-in collating sequence that compares string data
- * using SQLite's memcmp() function, regardless of text encoding.
- * 
- * @author Adrian Cole
- * @see <a
- *      href="http://docs.openstack.org/api/openstack-object-storage/1.0/content/s_listcontainers.html">api
- *      doc</a>
- */
-public class ContainerMetadata implements Comparable<ContainerMetadata> {
-
-   public static Builder builder() {
-      return new Builder();
-   }
-
-   public Builder toBuilder() {
-      return builder().fromAccountMetadata(this);
-   }
-
-   public static class Builder {
-      protected String name;
-      protected int count;
-      protected int bytes;
-
-      /**
-       * @see ContainerMetadata#getName()
-       */
-      public Builder name(String name) {
-         this.name = checkNotNull(name, "name");
-         return this;
-      }
-
-      /**
-       * @see ContainerMetadata#getCount()
-       */
-      public Builder count(int count) {
-         this.count = count;
-         return this;
-      }
-
-      /**
-       * @see ContainerMetadata#getBytes()
-       */
-      public Builder bytes(int bytes) {
-         this.bytes = bytes;
-         return this;
-      }
-
-      public ContainerMetadata build() {
-         return new ContainerMetadata(name, count, bytes);
-      }
-
-      public Builder fromAccountMetadata(ContainerMetadata from) {
-         return name(from.getName()).count(from.getCount()).bytes(from.getBytes());
-      }
-   }
-  
-   protected String name;
-   protected int count;
-   protected int bytes;
-
-   @ConstructorProperties({"name", "count", "bytes"})
-   protected ContainerMetadata(String name, int count, int bytes) {
-      this.name = checkNotNull(name, "name");
-      this.count = count;
-      this.bytes = bytes;
-   }
-
-   /**
-    * 
-    * @return the name of the container
-    */
-   public String getName() {
-      return name;
-   }
-
-   /**
-    * 
-    * @return the number of objects in the container
-    */
-   public int getCount() {
-      return count;
-   }
-
-   /**
-    * @return the total bytes stored in this container
-    */
-   public int getBytes() {
-      return bytes;
-   }
-
-   @Override
-   public boolean equals(Object object) {
-      if (this == object) {
-         return true;
-      }
-      if (object instanceof ContainerMetadata) {
-         final ContainerMetadata other = ContainerMetadata.class.cast(object);
-         return equal(getName(), other.getName()) && equal(getCount(), other.getCount())
-                  && equal(getBytes(), other.getBytes());
-      } else {
-         return false;
-      }
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(getName(), getCount(), getBytes());
-   }
-
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-   protected ToStringHelper string() {
-      return toStringHelper("").add("name", getName()).add("count", getCount()).add("bytes", getBytes());
-   }
-
-   @Override
-   public int compareTo(ContainerMetadata that) {
-      if (that == null)
-         return 1;
-      if (this == that)
-         return 0;
-      return this.getName().compareTo(that.getName());
-   }
-
-}
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
index 1cf2e2b..78d8a31 100644
--- a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountApi.java
@@ -18,13 +18,10 @@
  */
 package org.jclouds.openstack.swift.v1.features;
 
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
-import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
-import org.jclouds.openstack.swift.v1.domain.ContainerMetadata;
-import org.jclouds.openstack.swift.v1.options.ListContainersOptions;
+import org.jclouds.openstack.swift.v1.domain.Account;
 
 /**
  * Storage Account Services
@@ -37,26 +34,12 @@
  */
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface AccountApi {
+   
    /**
     * Retrieve Account Metadata
     * 
     * @return account metadata including container count and bytes used
     */
-   AccountMetadata getAccountMetadata();
-
-   /**
-    * @see #listContainers(ListContainersOptions)
-    */
-   Set<? extends ContainerMetadata> listContainers();
-
-   /**
-    * retrieve a list of existing storage containers ordered by name. The sort order for the name is
-    * based on a binary comparison, a single built-in collating sequence that compares string data
-    * using SQLite's memcmp() function, regardless of text encoding.
-    * 
-    * @param options
-    * @return a list of existing storage containers ordered by name.
-    */
-   Set<? extends ContainerMetadata> listContainers(ListContainersOptions options);
+   Account get();
 
 }
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountAsyncApi.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountAsyncApi.java
index de64dee..9473428 100644
--- a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountAsyncApi.java
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/AccountAsyncApi.java
@@ -18,25 +18,15 @@
  */
 package org.jclouds.openstack.swift.v1.features;
 
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
 import javax.ws.rs.HEAD;
 import javax.ws.rs.Path;
-import javax.ws.rs.core.MediaType;
 
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
-import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
-import org.jclouds.openstack.swift.v1.domain.ContainerMetadata;
+import org.jclouds.openstack.swift.v1.domain.Account;
 import org.jclouds.openstack.swift.v1.functions.ParseAccountMetadataResponseFromHeaders;
-import org.jclouds.openstack.swift.v1.options.ListContainersOptions;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.QueryParams;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -54,30 +44,11 @@
 public interface AccountAsyncApi {
 
    /**
-    * @see AccountApi#getAccountMetadata
+    * @see AccountApi#get
     */
    @HEAD
    @ResponseParser(ParseAccountMetadataResponseFromHeaders.class)
    @Path("/")
-   ListenableFuture<? extends AccountMetadata> getAccountMetadata();
+   ListenableFuture<? extends Account> get();
 
-   /**
-    * @see AccountApi#listContainers()
-    */
-   @GET
-   @Consumes(MediaType.APPLICATION_JSON)
-   @QueryParams(keys = "format", values = "json")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   @Path("/")
-   ListenableFuture<? extends Set<? extends ContainerMetadata>> listContainers();
-
-   /**
-    * @see AccountApi#listContainers(ListContainersOptions)
-    */
-   @GET
-   @Consumes(MediaType.APPLICATION_JSON)
-   @QueryParams(keys = "format", values = "json")
-   @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
-   @Path("/")
-   ListenableFuture<? extends Set<? extends ContainerMetadata>> listContainers(ListContainersOptions options);
 }
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
index 7da668e..f87e2b4 100644
--- a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerApi.java
@@ -21,6 +21,10 @@
 import java.util.concurrent.TimeUnit;
 
 import org.jclouds.concurrent.Timeout;
+import org.jclouds.openstack.swift.v1.domain.Container;
+import org.jclouds.openstack.swift.v1.options.ListContainersOptions;
+
+import com.google.common.collect.FluentIterable;
 
 /**
  * Storage Container Services
@@ -34,4 +38,19 @@
 @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
 public interface ContainerApi {
 
+   /**
+    * @see #list(ListContainersOptions)
+    */
+   FluentIterable<? extends Container> list();
+
+   /**
+    * retrieve a list of existing storage containers ordered by name. The sort order for the name is
+    * based on a binary comparison, a single built-in collating sequence that compares string data
+    * using SQLite's memcmp() function, regardless of text encoding.
+    * 
+    * @param options
+    * @return a list of existing storage containers ordered by name.
+    */
+   FluentIterable<? extends Container> list(ListContainersOptions options);
+
 }
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerAsyncApi.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerAsyncApi.java
index 996d6a2..b5978b1 100644
--- a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerAsyncApi.java
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/features/ContainerAsyncApi.java
@@ -18,9 +18,22 @@
  */
 package org.jclouds.openstack.swift.v1.features;
 
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.swift.v1.domain.Container;
+import org.jclouds.openstack.swift.v1.options.ListContainersOptions;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.QueryParams;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * Storage Container Services
@@ -35,4 +48,23 @@
 @RequestFilters(AuthenticateRequest.class)
 public interface ContainerAsyncApi {
 
+   /**
+    * @see ContainerApi#list()
+    */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @QueryParams(keys = "format", values = "json")
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   @Path("/")
+   ListenableFuture<? extends FluentIterable<? extends Container>> list();
+
+   /**
+    * @see ContainerApi#list(ListContainersOptions)
+    */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @QueryParams(keys = "format", values = "json")
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   @Path("/")
+   ListenableFuture<? extends FluentIterable<? extends Container>> list(ListContainersOptions options);
 }
diff --git a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java
index e01ccad..d0271e6 100644
--- a/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java
+++ b/labs/openstack-swift/src/main/java/org/jclouds/openstack/swift/v1/functions/ParseAccountMetadataResponseFromHeaders.java
@@ -19,22 +19,22 @@
 package org.jclouds.openstack.swift.v1.functions;
 
 import org.jclouds.http.HttpResponse;
-import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
+import org.jclouds.openstack.swift.v1.domain.Account;
 
 import com.google.common.base.Function;
 
 /**
- * This parses {@link AccountMetadata} from HTTP headers.
+ * This parses {@link Account} from HTTP headers.
  * 
  * @author James Murty
  */
-public class ParseAccountMetadataResponseFromHeaders implements Function<HttpResponse, AccountMetadata> {
+public class ParseAccountMetadataResponseFromHeaders implements Function<HttpResponse, Account> {
 
    /**
-    * parses the http response headers to create a new {@link AccountMetadata} object.
+    * parses the http response headers to create a new {@link Account} object.
     */
-   public AccountMetadata apply(HttpResponse from) {
-      return AccountMetadata.builder()
+   public Account apply(HttpResponse from) {
+      return Account.builder()
                .bytesUsed(Long.parseLong(from.getFirstHeaderOrNull("X-Account-Bytes-Used")))
                .containerCount(Integer.parseInt(from.getFirstHeaderOrNull("X-Account-Container-Count")))
                .build();
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java
index 1678c14..fa0006e 100644
--- a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/PasswordAuthenticationExpectTest.java
@@ -50,22 +50,22 @@
    }
 
    public void testListContainersWhenResponseIs2xx() throws Exception {
-      HttpRequest listContainers = HttpRequest
+      HttpRequest list = HttpRequest
             .builder()
             .method("GET")
             .endpoint("https://objects.jclouds.org/v1.0/40806637803162/?format=json")
             .addHeader("Accept", "application/json")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listContainersResponse = HttpResponse.builder().statusCode(200)
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
             .payload(payloadFromResource("/container_list.json")).build();
 
       SwiftApi apiWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, listContainers, listContainersResponse);
+            responseWithKeystoneAccess, list, listResponse);
 
       assertEquals(apiWhenContainersExist.getConfiguredRegions(), ImmutableSet.of("region-a.geo-1"));
 
-      assertEquals(apiWhenContainersExist.getAccountApiForRegion("region-a.geo-1").listContainers().toString(),
+      assertEquals(apiWhenContainersExist.getContainerApiForRegion("region-a.geo-1").list().toString(),
             new ParseContainerListTest().expected().toString());
    }
 
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiExpectTest.java
index edf50af..edffd00 100644
--- a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiExpectTest.java
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiExpectTest.java
@@ -23,13 +23,10 @@
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.HttpResponse;
 import org.jclouds.openstack.swift.v1.SwiftApi;
-import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
+import org.jclouds.openstack.swift.v1.domain.Account;
 import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiExpectTest;
-import org.jclouds.openstack.swift.v1.parse.ParseContainerListTest;
 import org.testng.annotations.Test;
 
-import com.google.common.collect.ImmutableSet;
-
 /**
  * @author Adrian Cole
  */
@@ -38,59 +35,23 @@
    
    public void testGetAccountMetadataWhenResponseIs2xx() throws Exception {
 
-      HttpRequest getAccountMetadata = HttpRequest
+      HttpRequest get = HttpRequest
             .builder()
             .method("HEAD")
             .endpoint("https://objects.jclouds.org/v1.0/40806637803162/")
             .addHeader("X-Auth-Token", authToken).build();
 
-      HttpResponse listContainersResponse = HttpResponse.builder().statusCode(204)
+      HttpResponse listResponse = HttpResponse.builder().statusCode(204)
             .addHeader("X-Account-Container-Count", "3")
             .addHeader("X-Account-Bytes-Used", "323479").build();
 
-      SwiftApi apiWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, getAccountMetadata, listContainersResponse);
+      SwiftApi apiWhenExists = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+            responseWithKeystoneAccess, get, listResponse);
 
       assertEquals(
-            apiWhenContainersExist.getAccountApiForRegion("region-a.geo-1").getAccountMetadata(),
-            AccountMetadata.builder().containerCount(3).bytesUsed(323479).build());
+            apiWhenExists.getAccountApiForRegion("region-a.geo-1").get(),
+            Account.builder().containerCount(3).bytesUsed(323479).build());
    }
    
-   public void testListContainersWhenResponseIs2xx() throws Exception {
-
-      HttpRequest listContainers = HttpRequest
-            .builder()
-            .method("GET")
-            .endpoint("https://objects.jclouds.org/v1.0/40806637803162/?format=json")
-            .addHeader("Accept", "application/json")
-            .addHeader("X-Auth-Token", authToken).build();
-
-      HttpResponse listContainersResponse = HttpResponse.builder().statusCode(200)
-            .payload(payloadFromResource("/container_list.json")).build();
-
-      SwiftApi apiWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, listContainers, listContainersResponse);
-
-      assertEquals(
-            apiWhenContainersExist.getAccountApiForRegion("region-a.geo-1").listContainers()
-                  .toString(), new ParseContainerListTest().expected().toString());
-   }
-
-   public void testListContainersWhenResponseIs404() throws Exception {
-      HttpRequest listContainers = HttpRequest
-            .builder()
-            .method("GET")
-            .endpoint("https://objects.jclouds.org/v1.0/40806637803162/?format=json")
-            .addHeader("Accept", "application/json")
-            .addHeader("X-Auth-Token", authToken).build();
-
-      HttpResponse listContainersResponse = HttpResponse.builder().statusCode(404).build();
-
-      SwiftApi apiWhenNoContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
-            responseWithKeystoneAccess, listContainers, listContainersResponse);
-
-      assertEquals(apiWhenNoContainersExist.getAccountApiForRegion("region-a.geo-1").listContainers(), ImmutableSet.of());
-
-   }
 
 }
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
index 8521c0e..6232d6d 100644
--- a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/AccountApiLiveTest.java
@@ -21,10 +21,7 @@
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 
-import java.util.Set;
-
-import org.jclouds.openstack.swift.v1.domain.AccountMetadata;
-import org.jclouds.openstack.swift.v1.domain.ContainerMetadata;
+import org.jclouds.openstack.swift.v1.domain.Account;
 import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
 import org.testng.annotations.Test;
 
@@ -38,24 +35,11 @@
    public void testGetAccountMetadata() throws Exception {
       for (String regionId : swiftContext.getApi().getConfiguredRegions()) {
          AccountApi api = swiftContext.getApi().getAccountApiForRegion(regionId);
-         AccountMetadata account = api.getAccountMetadata();
+         Account account = api.get();
          assertNotNull(account);
          assertTrue(account.getContainerCount() >= 0);
          assertTrue(account.getBytesUsed() >= 0);
       }
    }
 
-   @Test
-   public void testListContainers() throws Exception {
-      for (String regionId : swiftContext.getApi().getConfiguredRegions()) {
-         AccountApi api = swiftContext.getApi().getAccountApiForRegion(regionId);
-         Set<? extends ContainerMetadata> response = api.listContainers();
-         assertNotNull(response);
-         for (ContainerMetadata container : response) {
-            assertNotNull(container.getName());
-            assertTrue(container.getCount() >= 0);
-            assertTrue(container.getBytes() >= 0);
-         }
-      }
-   }
 }
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiExpectTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiExpectTest.java
index 0982343..eec3a43 100644
--- a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiExpectTest.java
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiExpectTest.java
@@ -18,14 +18,59 @@
  */
 package org.jclouds.openstack.swift.v1.features;
 
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.swift.v1.SwiftApi;
 import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiExpectTest;
+import org.jclouds.openstack.swift.v1.parse.ParseContainerListTest;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.ImmutableSet;
+
 /**
  * 
  * @author Adrian Cole
  */
 @Test(groups = "unit", testName = "ContainerAsyncApiTest")
 public class ContainerApiExpectTest extends BaseSwiftApiExpectTest {
+   public void testListContainersWhenResponseIs2xx() throws Exception {
+
+      HttpRequest list = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://objects.jclouds.org/v1.0/40806637803162/?format=json")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken).build();
+
+      HttpResponse listResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/container_list.json")).build();
+
+      SwiftApi apiWhenContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+            responseWithKeystoneAccess, list, listResponse);
+
+      assertEquals(
+            apiWhenContainersExist.getContainerApiForRegion("region-a.geo-1").list()
+                  .toString(), new ParseContainerListTest().expected().toString());
+   }
+
+   public void testListContainersWhenResponseIs404() throws Exception {
+      HttpRequest list = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint("https://objects.jclouds.org/v1.0/40806637803162/?format=json")
+            .addHeader("Accept", "application/json")
+            .addHeader("X-Auth-Token", authToken).build();
+
+      HttpResponse listResponse = HttpResponse.builder().statusCode(404).build();
+
+      SwiftApi apiWhenNoContainersExist = requestsSendResponses(keystoneAuthWithUsernameAndPassword,
+            responseWithKeystoneAccess, list, listResponse);
+
+      assertEquals(apiWhenNoContainersExist.getContainerApiForRegion("region-a.geo-1").list().toImmutableSet(),
+               ImmutableSet.of());
+
+   }
 
 }
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
index 909e8bd..031ef21 100644
--- a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/features/ContainerApiLiveTest.java
@@ -18,9 +18,15 @@
  */
 package org.jclouds.openstack.swift.v1.features;
 
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import org.jclouds.openstack.swift.v1.domain.Container;
 import org.jclouds.openstack.swift.v1.internal.BaseSwiftApiLiveTest;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.FluentIterable;
+
 /**
  * 
  * @author Adrian Cole
@@ -28,4 +34,17 @@
 @Test(groups = "live", testName = "ContainerApiLiveTest")
 public class ContainerApiLiveTest extends BaseSwiftApiLiveTest {
 
+   @Test
+   public void testListContainers() throws Exception {
+      for (String regionId : swiftContext.getApi().getConfiguredRegions()) {
+         ContainerApi api = swiftContext.getApi().getContainerApiForRegion(regionId);
+         FluentIterable<? extends Container> response = api.list();
+         assertNotNull(response);
+         for (Container container : response) {
+            assertNotNull(container.getName());
+            assertTrue(container.getCount() >= 0);
+            assertTrue(container.getBytes() >= 0);
+         }
+      }
+   }
 }
diff --git a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
index 3c58312..7cc36c3 100644
--- a/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
+++ b/labs/openstack-swift/src/test/java/org/jclouds/openstack/swift/v1/parse/ParseContainerListTest.java
@@ -24,7 +24,7 @@
 import javax.ws.rs.core.MediaType;
 
 import org.jclouds.json.BaseSetParserTest;
-import org.jclouds.openstack.swift.v1.domain.ContainerMetadata;
+import org.jclouds.openstack.swift.v1.domain.Container;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableSet;
@@ -34,7 +34,7 @@
  * @author Adrian Cole
  */
 @Test(groups = "unit", testName = "ParseContainerListTest")
-public class ParseContainerListTest extends BaseSetParserTest<ContainerMetadata> {
+public class ParseContainerListTest extends BaseSetParserTest<Container> {
 
    @Override
    public String resource() {
@@ -43,14 +43,14 @@
 
    @Override
    @Consumes(MediaType.APPLICATION_JSON)
-   public Set<ContainerMetadata> expected() {
+   public Set<Container> expected() {
       return ImmutableSet
-            .of(ContainerMetadata.builder()
+            .of(Container.builder()
                   .name("test_container_1")
                   .count(2)
                   .bytes(78)
                   .build(),
-                ContainerMetadata.builder()
+                Container.builder()
                   .name("test_container_2")
                   .count(1)
                   .bytes(17)
diff --git a/labs/pom.xml b/labs/pom.xml
index 0ddb6ed..d3e782e 100644
--- a/labs/pom.xml
+++ b/labs/pom.xml
@@ -34,7 +34,6 @@
     <modules>
        <module>virtualbox</module>
        <module>vcloud-director</module>
-       <module>glesys</module>
        <module>opsource-servers</module>
        <module>elb</module>
        <module>aws-elb</module>
@@ -61,5 +60,6 @@
        <module>fgcp</module>
        <module>fgcp-au</module>
        <module>fgcp-de</module>
+       <module>abiquo</module>
     </modules>
 </project>
diff --git a/labs/savvis-symphonyvpdc/src/test/java/org/jclouds/savvis/vpdc/features/BrowsingAsyncApiTest.java b/labs/savvis-symphonyvpdc/src/test/java/org/jclouds/savvis/vpdc/features/BrowsingAsyncApiTest.java
index 0aa9a1b..b55ab50 100644
--- a/labs/savvis-symphonyvpdc/src/test/java/org/jclouds/savvis/vpdc/features/BrowsingAsyncApiTest.java
+++ b/labs/savvis-symphonyvpdc/src/test/java/org/jclouds/savvis/vpdc/features/BrowsingAsyncApiTest.java
@@ -42,7 +42,7 @@
  * 
  * @author Adrian Cole
  */
-@Test(groups = "unit")
+@Test(groups = "unit", testName = "BrowsingAsyncApiTest")
 public class BrowsingAsyncApiTest extends BaseVPDCAsyncApiTest<BrowsingAsyncApi> {
 
    public void testOrg() throws SecurityException, NoSuchMethodException, IOException {
diff --git a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/admin/AdminCatalogApiExpectTest.java b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/admin/AdminCatalogApiExpectTest.java
index c6af0da..4032b32 100644
--- a/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/admin/AdminCatalogApiExpectTest.java
+++ b/labs/vcloud-director/src/test/java/org/jclouds/vcloud/director/v1_5/features/admin/AdminCatalogApiExpectTest.java
@@ -50,7 +50,7 @@
  * 
  * @author grkvlt@apache.org, Adrian Cole
  */
-@Test(groups = { "unit", "admin" }, singleThreaded = true, testName = "CatalogApiExpectTest")
+@Test(groups = { "unit", "admin" }, singleThreaded = true, testName = "AdminCatalogApiExpectTest")
 public class AdminCatalogApiExpectTest extends VCloudDirectorAdminApiExpectTest {
    
    static String catalog = "7212e451-76e1-4631-b2de-ba1dfd8080e4";
diff --git a/labs/virtualbox/README.md b/labs/virtualbox/README.md
index 9b7e26d..b618fa9 100644
--- a/labs/virtualbox/README.md
+++ b/labs/virtualbox/README.md
@@ -1,11 +1,19 @@
 
 #Setup
 
-Have virtualbox 4.1.8 installed. 
+Have virtualbox 4.1.20r80170 installed. 
 
 Have an ssh daemon with passwordless login to localhost (i.e. "ssh [me]@localhost" must work without password).
+To achieve that, be sure you have your ssh public key (at System.getProperty("user.home") + "/.ssh/id_rsa") in your '.ssh/authorized_keys'.
+Please look at [this example]http://www.linuxproblem.org/art_9.html for more details.
 
-That's it! 
+You can have also specify '-Dvirtualbox.identity' and '-Dvirtualbox.credential' if you want to use a username and password of your local machine.
+
+In order to make available a preseed file, jclouds-vbox will start a PreseedServer at `http://localhost:23232` that will serve a preseed.cfg file.
+Make sure your firewall rules are not blocking this port.
+If you need to override this default you can use -Djclouds.virtualbox.preconfigurationurl=http://localhost:PORT/preseed.cfg, with a different PORT.
+
+That's it!
 
 --------------
 
@@ -17,7 +25,7 @@
 
 > (use 'org.jclouds.compute2)  
 > (import 'org.jclouds.scriptbuilder.statements.login.AdminAccess)  
-> (def compute (compute-service "virtualbox" "admin" "12345" :sshj :slf4j))  
+> (def compute (compute-service "virtualbox" "user" "password" :sshj :slf4j))  
 > (create-nodes compute "local-cluster" 2 (build-template compute { :run-script (AdminAccess/standard) } ))  
 
 --------------
@@ -39,8 +47,8 @@
 
 - jclouds-vbox is still at alpha stage please report any issues you find.  
 - jclouds-vbox has been mostly tested on Mac OSX, it might work on Linux iff vbox is running and correctly set up, but it won't work on windows for the moment.  
-- cached isos, vm's and most configs are kept at ~/.jclouds-vbox/ by default.  
-- jclouds-vbox assumes vbox has the default host-only network vboxnet0, that the network is in 192.168.86.0/255.255.255.0 and that the host has address 1 in this network.  
+- cached isos, vm's and most configs are kept at ~/.jclouds-vbox/ by default, you can override -Dtest.virtualbox.workingDir=/path/to/your/workingDir.
+- jclouds-vbox assumes vbox has the default host-only network vboxnet0, that the network is in 192.168.86.0/255.255.255.0 and that the host has address 1 in this network.
 
 --------------
 
diff --git a/labs/virtualbox/pom.xml b/labs/virtualbox/pom.xml
index 8112b68..2880858 100644
--- a/labs/virtualbox/pom.xml
+++ b/labs/virtualbox/pom.xml
@@ -36,10 +36,10 @@
   <properties>
     <test.virtualbox.endpoint>http://localhost:18083/</test.virtualbox.endpoint>
     <test.virtualbox.api-version>4.1.4</test.virtualbox.api-version>
-    <test.virtualbox.build-version>4.1.8r75467</test.virtualbox.build-version>
+    <test.virtualbox.build-version>4.1.20r80170</test.virtualbox.build-version>
     <test.virtualbox.identity>administrator</test.virtualbox.identity>
-    <test.virtualbox.credential>12345</test.virtualbox.credential>
-    <test.virtualbox.template>imageId=test-ubuntu-11.10-i386,loginUser=toor:password,authenticateSudo=true</test.virtualbox.template>
+    <test.virtualbox.credential>CHANGE_ME</test.virtualbox.credential>
+    <test.virtualbox.template>osFamily=UBUNTU,osVersionMatches=12.04.1,os64Bit=true,osArchMatches=amd64,loginUser=toor:password,authenticateSudo=true</test.virtualbox.template>
     <jclouds.osgi.export>org.jclouds.virtualbox*;version="${project.version}"</jclouds.osgi.export>
     <jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
   </properties>
@@ -135,6 +135,7 @@
                 </goals>
                 <configuration>
                   <threadCount>1</threadCount>
+                  <parallel>false</parallel>
                   <systemPropertyVariables>
                     <test.virtualbox.endpoint>${test.virtualbox.endpoint}</test.virtualbox.endpoint>
                     <test.virtualbox.api-version>${test.virtualbox.api-version}</test.virtualbox.api-version>
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxApiMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxApiMetadata.java
index f7c1b7f..6fd6004 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxApiMetadata.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/VirtualBoxApiMetadata.java
@@ -20,6 +20,8 @@
 
 import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGES_DESCRIPTOR;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_PRECONFIGURATION_URL;
@@ -81,7 +83,13 @@
       properties.put(VIRTUALBOX_IMAGES_DESCRIPTOR, yamlDescriptor);
 
       properties.put(VIRTUALBOX_PRECONFIGURATION_URL, "http://10.0.2.2:23232/preseed.cfg");
-      properties.setProperty(TEMPLATE, "osFamily=UBUNTU,osVersionMatches=11.10,os64Bit=true,osArchMatches=x86,loginUser=toor:password,authenticateSudo=true");
+      
+      properties.put(VIRTUALBOX_GUEST_IDENTITY, "toor");
+      properties.put(VIRTUALBOX_GUEST_CREDENTIAL, "password");
+      properties.setProperty(TEMPLATE, 
+            String.format("osFamily=UBUNTU,osVersionMatches=12.04.1,os64Bit=true,osArchMatches=amd64,loginUser=%s:%s,authenticateSudo=true", 
+                  properties.getProperty(VIRTUALBOX_GUEST_IDENTITY), 
+                  properties.getProperty(VIRTUALBOX_GUEST_CREDENTIAL)));
       return properties;
    }
 
@@ -93,8 +101,8 @@
          .identityName("User")
          .credentialName("Password")
          .documentation(URI.create("https://www.virtualbox.org/sdkref/index.html"))
-         .defaultIdentity("administrator")
-         .defaultCredential("12345")
+         .defaultIdentity(System.getProperty("user.name"))
+         .defaultCredential("CHANGE_ME")
          .defaultEndpoint("http://localhost:18083/")
          .documentation(URI.create("https://github.com/jclouds/jclouds/tree/master/apis/byon"))
           // later version not in maven, yet
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/HardcodeLocalhostAsNodeMetadataSupplier.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/HardcodeLocalhostAsNodeMetadataSupplier.java
index 814a6c9..ce598d4 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/HardcodeLocalhostAsNodeMetadataSupplier.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/HardcodeLocalhostAsNodeMetadataSupplier.java
@@ -35,6 +35,7 @@
 import org.jclouds.domain.LoginCredentials;
 
 import com.google.common.base.Charsets;
+import com.google.common.base.Strings;
 import com.google.common.base.Supplier;
 import com.google.common.base.Throwables;
 import com.google.common.io.Files;
@@ -79,7 +80,7 @@
 public class HardcodeLocalhostAsNodeMetadataSupplier extends AbstractModule {
 
    public static final String HOST_ID = "host";
-   public static final String HOSTNAME = System.getenv("HOSTNAME");
+   public static final String HOSTNAME = Strings.nullToEmpty(System.getenv("HOSTNAME"));
 
    /**
     * Lazy so that we don't hang up the injector reading a file
@@ -91,9 +92,7 @@
 
          @Override
          public NodeMetadata get() {
-
             String privateKey = readRsaIdentity();
-
             return new NodeMetadataBuilder()
                                     .id(HOST_ID)
                                     .name("host installing virtualbox")
@@ -110,9 +109,9 @@
                                                                    .description(HOSTNAME)
                                                                    .build())
                                     .credentials(LoginCredentials.builder()
-                                                                 .user(System.getProperty("user.name"))
-                                                                 .privateKey(privateKey)
-                                                                 .build())
+                                    		.user(System.getProperty("user.name"))
+                                    		.privateKey(privateKey)					 
+                                    		.build())
                                     .build();
          }
 
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
index 7fe2b90..d65bd85 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxComputeServiceContextModule.java
@@ -150,7 +150,10 @@
 
          @Override
          public VirtualBoxManager apply(Supplier<NodeMetadata> nodeSupplier) {
-            return VirtualBoxManager.createInstance(nodeSupplier.get().getId());
+            if(nodeSupplier.get().getId() != null)
+            	return VirtualBoxManager.createInstance(nodeSupplier.get().getId());
+
+           	return VirtualBoxManager.createInstance("");
          }
 
          @Override
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java
index 46a6e67..e0c8442 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/config/VirtualBoxConstants.java
@@ -61,5 +61,8 @@
             + ".jclouds-vbox";
    
    public static final String VIRTUALBOX_PROVIDER = "virtualbox";
+   
+   public static final String VIRTUALBOX_GUEST_IDENTITY = "jclouds.virtualbox.guest.identity";
+   public static final String VIRTUALBOX_GUEST_CREDENTIAL = "jclouds.virtualbox.guest.credential";
 
 }
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/YamlImage.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/YamlImage.java
index bff48a2..8a45140 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/YamlImage.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/domain/YamlImage.java
@@ -118,6 +118,7 @@
    public String os_family;
    public String os_description;
    public String os_version;
+   public String iso_md5;
    public String iso;
    public String keystroke_sequence;
    public String preseed_cfg;
@@ -154,7 +155,7 @@
    public String toString() {
       return "YamlImage [id=" + id + ", name=" + name + ", description=" + description + ", hostname=" + hostname
                + ", location_id=" + location_id + ", os_arch=" + os_arch + ", os_family=" + os_family
-               + ", os_description=" + os_description + ", os_version=" + os_version + ", iso=" + iso
+               + ", os_description=" + os_description + ", os_version=" + os_version + ", iso=" + iso 
                + ", keystroke_sequence=" + keystroke_sequence + ", preseed_cfg=" + preseed_cfg + ", login_port="
                + login_port + ", os_64bit=" + os_64bit + ", group=" + group + ", tags=" + tags + ", metadata="
                + metadata + ", username=" + username + ", credential=" + credential + ", credential_url="
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
index 46521df..0985deb 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CloneAndRegisterMachineFromIMachineIfNotAlreadyExists.java
@@ -21,6 +21,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
 
 import javax.annotation.Resource;
 import javax.inject.Named;
@@ -60,6 +61,8 @@
    private final Supplier<VirtualBoxManager> manager;
    private final String workingDir;
    private final MachineUtils machineUtils;
+   
+   private final ReentrantLock lock = new ReentrantLock();
 
    @Inject
    public CloneAndRegisterMachineFromIMachineIfNotAlreadyExists(Supplier<VirtualBoxManager> manager,
@@ -104,15 +107,13 @@
       if (isLinkedClone)
          options.add(CloneOptions.Link);
 
-      // TODO snapshot name
-      ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc", logger)
-               .apply(master);
-
-      // clone
-      IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, CloneMode.MachineState, options);
-
+      ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager,
+            "snapshotName", "snapshotDesc", logger).apply(master);
+      IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine,
+            CloneMode.MachineState, options);
       progress.waitForCompletion(-1);
-      logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
+      logger.debug(String.format("Machine %s is cloned correctly",
+            clonedMachine.getName()));
 
       // memory may not be the same as the master vm
       clonedMachine.setMemorySize(cloneSpec.getVmSpec().getMemory());
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java
index b359cd4..ff013ed 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/CreateAndInstallVm.java
@@ -42,7 +42,9 @@
 import org.jclouds.virtualbox.statements.InstallGuestAdditions;
 import org.jclouds.virtualbox.util.MachineController;
 import org.jclouds.virtualbox.util.MachineUtils;
+import org.virtualbox_4_1.DeviceType;
 import org.virtualbox_4_1.IMachine;
+import org.virtualbox_4_1.IMediumAttachment;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
@@ -88,19 +90,14 @@
 
    @Override
    public IMachine apply(MasterSpec masterSpec) {
-
       VmSpec vmSpec = masterSpec.getVmSpec();
       IsoSpec isoSpec = masterSpec.getIsoSpec();
       String vmName = vmSpec.getVmName();
-
       IMachine vm = createAndRegisterMachineFromIsoIfNotAlreadyExists.apply(masterSpec);
-
       // Launch machine and wait for it to come online
       machineController.ensureMachineIsLaunched(vmName);
-
       String installationKeySequence = isoSpec.getInstallationKeySequence().replace("PRECONFIGURATION_URL",
                preconfigurationUrl);
-
       configureOsInstallationWithKeyboardSequence(vmName, installationKeySequence);
 
       // the OS installation is a long process: let's delay the check for ssh of 30 sec
@@ -111,11 +108,8 @@
       }
 
       SshClient client = sshClientForIMachine.apply(vm);
-
       logger.debug(">> awaiting installation to finish node(%s)", vmName);
-
       checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh", vmName);
-
       NodeMetadata nodeMetadata = imachineToNodeMetadata.apply(vm);
 
       logger.debug(">> awaiting post-installation actions on vm: %s", vmName);
@@ -129,9 +123,17 @@
                new InstallGuestAdditions(vmSpec, version), RunScriptOptions.NONE);
       ExecResponse gaInstallationResponse = Futures.getUnchecked(execInstallGA);
       checkState(gaInstallationResponse.getExitStatus() == 0);
-
       machineController.ensureMachineIsShutdown(vmName);
-
+      Iterable<IMediumAttachment> mediumAttachments = Iterables.filter(vm.getMediumAttachmentsOfController("IDE Controller"),
+              new Predicate<IMediumAttachment>() {
+                 public boolean apply(IMediumAttachment in) {
+                    return in.getMedium() != null && in.getMedium().getDeviceType().equals(DeviceType.DVD);
+                 }
+              });
+      for (IMediumAttachment iMediumAttachment : mediumAttachments) {
+          machineUtils.writeLockMachineAndApply(vm.getName(), new DetachDistroMediumFromMachine(
+        		  iMediumAttachment.getController(), iMediumAttachment.getPort(), iMediumAttachment.getDevice()));
+   	}
       return vm;
    }
 
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/HardcodedHostToHostNodeMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/HardcodedHostToHostNodeMetadata.java
new file mode 100644
index 0000000..8f09c67
--- /dev/null
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/HardcodedHostToHostNodeMetadata.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.virtualbox.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+
+import javax.annotation.Resource;
+import javax.inject.Named;
+
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.Provider;
+import org.jclouds.logging.Logger;
+import org.jclouds.rest.annotations.Credential;
+import org.jclouds.rest.annotations.Identity;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class HardcodedHostToHostNodeMetadata implements
+      Function<NodeMetadata, NodeMetadata> {
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final Supplier<URI> providerSupplier;
+   private final String username;
+   private final String password;
+
+   @Inject
+   public HardcodedHostToHostNodeMetadata(
+         @Provider Supplier<URI> providerSupplier,
+         @Nullable @Identity String identity,
+         @Nullable @Credential String credential) {
+      this.providerSupplier = checkNotNull(providerSupplier,
+            "endpoint to virtualbox websrvd is needed");
+      this.username = identity;
+      this.password = credential.equals("CHANGE_ME") ? "" : credential;
+   }
+
+   @Override
+   public NodeMetadata apply(NodeMetadata host) {
+
+      LoginCredentials.Builder credentialsBuilder = LoginCredentials.builder(
+            host.getCredentials()).user(username);
+      if (!password.isEmpty())
+         credentialsBuilder.password(password);
+
+      return NodeMetadataBuilder
+            .fromNodeMetadata(host)
+            .credentials(credentialsBuilder.build())
+            .publicAddresses(ImmutableList.of(providerSupplier.get().getHost()))
+            .build();
+   }
+
+}
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
index d985d05..499fca7 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToNodeMetadata.java
@@ -46,7 +46,6 @@
 
 import com.google.common.base.Function;
 import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -82,7 +81,6 @@
       
       NodeMetadataBuilder nodeMetadataBuilder = new NodeMetadataBuilder();
       nodeMetadataBuilder.name(name).ids(vm.getName()).group(group);
-
       // TODO Set up location properly
       LocationBuilder locationBuilder = new LocationBuilder();
       locationBuilder.description("");
@@ -96,41 +94,8 @@
       if (nodeState == null)
          nodeState = Status.UNRECOGNIZED;
       nodeMetadataBuilder.status(nodeState);
-
-      /*
-      // nat adapter
-      INetworkAdapter natAdapter = vm.getNetworkAdapter(0l);
-      checkNotNull(natAdapter, "slot 0 networkadapter");
-      checkState(natAdapter.getAttachmentType() == NetworkAttachmentType.NAT,
-               "expecting slot 0 to be a NAT attachment type (was: " + natAdapter.getAttachmentType() + ")");
-
-      int ipTermination = 0;
-      int inPort = 0;
-      String hostAddress = "";
-
-      nodeMetadataBuilder.publicAddresses(ImmutableSet.of(natAdapter.getNatDriver().getHostIP()));
-      for (String nameProtocolnumberAddressInboudportGuestTargetport : natAdapter.getNatDriver().getRedirects()) {
-         Iterable<String> stuff = Splitter.on(',').split(nameProtocolnumberAddressInboudportGuestTargetport);
-         String protocolNumber = Iterables.get(stuff, 1);
-         hostAddress = Iterables.get(stuff, 2);
-         String inboundPort = Iterables.get(stuff, 3);
-         String targetPort = Iterables.get(stuff, 5);
-         if ("1".equals(protocolNumber) && "22".equals(targetPort)) {
-            inPort = Integer.parseInt(inboundPort);
-            ipTermination = inPort % NodeCreator.NODE_PORT_INIT + 2;
-         }
-      }
-      
-      // only masters use 2222 port
-      if (inPort == MastersLoadingCache.MASTER_PORT) {
-         nodeMetadataBuilder.publicAddresses(ImmutableSet.of(hostAddress)).loginPort(inPort);
-      } else {
-         nodeMetadataBuilder.privateAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + ""));
-         nodeMetadataBuilder.publicAddresses(ImmutableSet.of((NodeCreator.VMS_NETWORK + ipTermination) + ""));
-      } 
-      */
-      
       nodeMetadataBuilder = getIpAddresses(vm, nodeMetadataBuilder);
+      
       LoginCredentials loginCredentials = new LoginCredentials("toor", "password", null, true);
       nodeMetadataBuilder.credentials(loginCredentials);
 
@@ -144,7 +109,9 @@
          INetworkAdapter adapter = vm.getNetworkAdapter(slot);
          if(adapter != null) {
             if (adapter.getAttachmentType() == NetworkAttachmentType.NAT) {
-               publicIpAddresses.add(adapter.getNatDriver().getHostIP());
+               String hostIP = adapter.getNatDriver().getHostIP();
+               if(!hostIP.isEmpty())
+                  publicIpAddresses.add(hostIP);
                for (String nameProtocolnumberAddressInboudportGuestTargetport : adapter.getNatDriver().getRedirects()) {
                   Iterable<String> stuff = Splitter.on(',').split(nameProtocolnumberAddressInboudportGuestTargetport);
                   String protocolNumber = Iterables.get(stuff, 1);
@@ -153,26 +120,25 @@
                   String targetPort = Iterables.get(stuff, 5);
                   if ("1".equals(protocolNumber) && "22".equals(targetPort)) {
                      int inPort = Integer.parseInt(inboundPort);
-                     nodeMetadataBuilder.publicAddresses(ImmutableSet.of(hostAddress)).loginPort(inPort);
+                     publicIpAddresses.add(hostAddress);
+                     nodeMetadataBuilder.loginPort(inPort);
                   }
                   //privateIpAddresses.add((NodeCreator.VMS_NETWORK + ipTermination) + "");
                }
                // TODO this could be a public and private address
             } else if (adapter.getAttachmentType() == NetworkAttachmentType.Bridged) {
-               String clientIpAddress = machineUtils.getIpAddressFromBridgedNIC(vm.getName());
+               String clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
                //privateIpAddresses.add(clientIpAddress);
                publicIpAddresses.add(clientIpAddress);
 
             } else if (adapter.getAttachmentType() == NetworkAttachmentType.HostOnly) {
-               String clientIpAddress = machineUtils.getIpAddressFromHostOnlyNIC(vm.getName());
+               String clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
                publicIpAddresses.add(clientIpAddress);
-
             }
          }
       }
       nodeMetadataBuilder.publicAddresses(publicIpAddresses);
       nodeMetadataBuilder.privateAddresses(publicIpAddresses);
-
       return nodeMetadataBuilder;
    }   
 
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToSshClient.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToSshClient.java
index 3c68415..adb15aa 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToSshClient.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IMachineToSshClient.java
@@ -20,6 +20,8 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY;
 
 import java.util.List;
 
@@ -35,6 +37,7 @@
 import org.jclouds.domain.LoginCredentials;
 import org.jclouds.logging.Logger;
 import org.jclouds.ssh.SshClient;
+import org.jclouds.virtualbox.VirtualBoxApiMetadata;
 import org.jclouds.virtualbox.domain.BridgedIf;
 import org.jclouds.virtualbox.statements.GetIPAddressFromMAC;
 import org.jclouds.virtualbox.statements.ScanNetworkWithPing;
@@ -82,10 +85,11 @@
 		String clientIpAddress = null;
 		String sshPort = "22";
 
-		// TODO: we need a way to align the default login credentials
-		// from the iso with the vmspec -> IMachineToNodeMetadata using YamlImage ?
+      String guestIdentity = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_IDENTITY);
+      String guestCredential = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_CREDENTIAL);
 		LoginCredentials loginCredentials = LoginCredentials.builder()
-				.user("toor").password("password").authenticateSudo(true)
+				.user(guestIdentity)
+				.password(guestCredential).authenticateSudo(true)
 				.build();
 
 		if (networkAdapter.getAttachmentType()
@@ -109,7 +113,7 @@
 			clientIpAddress = getIpAddressFromBridgedNIC(networkAdapter, network);
 		} else if (networkAdapter.getAttachmentType().equals(
                         NetworkAttachmentType.HostOnly)) {
-	             clientIpAddress = machineUtils.getIpAddressFromHostOnlyNIC(vm.getName());
+	             clientIpAddress = machineUtils.getIpAddressFromFirstNIC(vm.getName());
 		}
 		
 		checkNotNull(clientIpAddress, "clientIpAddress");
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IpAddressesLoadingCache.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IpAddressesLoadingCache.java
new file mode 100644
index 0000000..c45112a
--- /dev/null
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/IpAddressesLoadingCache.java
@@ -0,0 +1,95 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.jclouds.virtualbox.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.logging.Logger;
+import org.jclouds.virtualbox.util.MachineUtils;
+import org.virtualbox_4_1.VirtualBoxManager;
+
+import com.google.common.base.Supplier;
+import com.google.common.cache.AbstractLoadingCache;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Maps;
+
+/**
+ * A {@link LoadingCache} for ip addresses. If the requested ip address has been
+ * previously extracted this returns it, if not it calls vbox api.
+ * 
+ * @author andrea turli
+ * 
+ */
+@Singleton
+public class IpAddressesLoadingCache extends
+      AbstractLoadingCache<String, String> {
+  
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final Map<String, String> masters = Maps.newHashMap();
+   private final Supplier<VirtualBoxManager> manager;
+
+   @Inject
+   public IpAddressesLoadingCache(Supplier<VirtualBoxManager> manager) {
+      this.manager = checkNotNull(manager, "vboxmanager");
+   }
+
+   @Override
+   public synchronized String get(String idOrName) throws ExecutionException {
+      if (masters.containsKey(idOrName)) {
+         return masters.get(idOrName);
+      }
+     
+      String currentIp = "", previousIp = "";
+      int count = 0;
+      while (count < 3) {
+         currentIp = "";
+         while (!MachineUtils.isIpv4(currentIp)) {
+            currentIp = manager.get().getVBox().findMachine(idOrName)
+                  .getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
+         }
+
+         if (previousIp.equals(currentIp)) {
+             count++;
+          }
+         previousIp = currentIp;
+      }
+
+      masters.put(idOrName, currentIp);
+      return currentIp;
+   }
+
+   @Override
+   public String getIfPresent(Object key) {
+      return masters.get((String) key);
+   }
+
+}
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
index 42f9506..04f6f4d 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/MastersLoadingCache.java
@@ -22,6 +22,7 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
+import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
@@ -32,6 +33,8 @@
 
 import java.io.File;
 import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ExecutionException;
@@ -42,10 +45,17 @@
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import org.jclouds.compute.callables.RunScriptOnNode.Factory;
+import org.jclouds.compute.domain.ExecResponse;
 import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.location.Provider;
 import org.jclouds.logging.Logger;
 import org.jclouds.rest.annotations.BuildVersion;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.StatementList;
+import org.jclouds.scriptbuilder.domain.Statements;
 import org.jclouds.virtualbox.domain.HardDisk;
 import org.jclouds.virtualbox.domain.IsoSpec;
 import org.jclouds.virtualbox.domain.Master;
@@ -57,6 +67,8 @@
 import org.jclouds.virtualbox.domain.VmSpec;
 import org.jclouds.virtualbox.domain.YamlImage;
 import org.jclouds.virtualbox.functions.admin.PreseedCfgServer;
+import org.jclouds.virtualbox.predicates.RetryIfSocketNotYetOpen;
+import org.testng.collections.Lists;
 import org.virtualbox_4_1.CleanupMode;
 import org.virtualbox_4_1.IMachine;
 import org.virtualbox_4_1.NetworkAttachmentType;
@@ -71,178 +83,236 @@
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
+import com.google.common.net.HostAndPort;
 
 /**
- * A {@link LoadingCache} for masters. If the requested master has been previously created this
- * returns it, if not it coordinates its creation including downloading isos and creating
- * cache/config directories. This also implements {@link Supplier} in order to provide jetty with
- * the current image (only one master can be created at a time).
+ * A {@link LoadingCache} for masters. If the requested master has been
+ * previously created this returns it, if not it coordinates its creation
+ * including downloading isos and creating cache/config directories. This also
+ * implements {@link Supplier} in order to provide jetty with the current image
+ * (only one master can be created at a time).
  * 
- * @author dralves
+ * @author dralves, andrea turli
  * 
  */
 @Singleton
 public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
 
-   // TODO parameterize
-   public static final int MASTER_PORT = 2222;
-   public static final String HOST_ONLY_IFACE_NAME = "vboxnet0";
+	// TODO parameterize
+	public static final int MASTER_PORT = 2222;
 
-   @Resource
-   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
-   protected Logger logger = Logger.NULL;
+	@Resource
+	@Named(ComputeServiceConstants.COMPUTE_LOGGER)
+	protected Logger logger = Logger.NULL;
 
-   private final Map<String, Master> masters = Maps.newHashMap();
-   private final Function<MasterSpec, IMachine> masterCreatorAndInstaller;
-   private final Map<String, YamlImage> imageMapping;
-   private final String workingDir;
-   private final String installationKeySequence;
-   private final String isosDir;
-   private final Supplier<VirtualBoxManager> manager;
-   private final Function<URI, File> isoDownloader;
-   private final String version;
-   private final String preconfigurationUrl;
+	private final Map<String, Master> masters = Maps.newHashMap();
+	private final Function<MasterSpec, IMachine> masterCreatorAndInstaller;
+	private final Map<String, YamlImage> imageMapping;
+	private final String workingDir;
+	private final String installationKeySequence;
+	private final String isosDir;
+	private final Supplier<VirtualBoxManager> manager;
+	private final String version;
+	private final String preconfigurationUrl;
 
-   @Inject
-   public MastersLoadingCache(@BuildVersion String version,
-            @Named(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) String installationKeySequence,
-            @Named(VIRTUALBOX_PRECONFIGURATION_URL) String preconfigurationUrl,
-            @Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<MasterSpec, IMachine> masterLoader,
-            Supplier<Map<Image, YamlImage>> yamlMapper, Supplier<VirtualBoxManager> manager,
-            Function<URI, File> isoDownloader) {
-      checkNotNull(version, "version");
-      checkNotNull(installationKeySequence, "installationKeySequence");
-      checkNotNull(manager, "vboxmanager");
-      this.manager = manager;
-      this.masterCreatorAndInstaller = masterLoader;
-      this.installationKeySequence = installationKeySequence;
-      this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
-      this.isosDir = workingDir + File.separator + "isos";
-      this.imageMapping = Maps.newLinkedHashMap();
-      for (Entry<Image, YamlImage> entry : yamlMapper.get().entrySet()) {
-         this.imageMapping.put(entry.getKey().getId(), entry.getValue());
+	private final Factory runScriptOnNodeFactory;
+	private final RetryIfSocketNotYetOpen socketTester;
+	private final Supplier<NodeMetadata> host;
+	private final Supplier<URI> providerSupplier;
+   private final HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata;
+
+	@Inject
+	public MastersLoadingCache(
+			@BuildVersion String version,
+			@Named(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE) String installationKeySequence,
+			@Named(VIRTUALBOX_PRECONFIGURATION_URL) String preconfigurationUrl,
+			@Named(VIRTUALBOX_WORKINGDIR) String workingDir,
+			Function<MasterSpec, IMachine> masterLoader,
+			Supplier<Map<Image, YamlImage>> yamlMapper,
+			Supplier<VirtualBoxManager> manager,
+			Factory runScriptOnNodeFactory,
+			RetryIfSocketNotYetOpen socketTester, Supplier<NodeMetadata> host,
+			@Provider Supplier<URI> providerSupplier,
+			HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata) {
+		checkNotNull(version, "version");
+		checkNotNull(installationKeySequence, "installationKeySequence");
+		checkNotNull(manager, "vboxmanager");
+		this.manager = manager;
+		this.masterCreatorAndInstaller = masterLoader;
+		this.installationKeySequence = installationKeySequence;
+		this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR
+				: workingDir;
+		this.isosDir = workingDir + File.separator + "isos";
+		this.imageMapping = Maps.newLinkedHashMap();
+		for (Entry<Image, YamlImage> entry : yamlMapper.get().entrySet()) {
+			this.imageMapping.put(entry.getKey().getId(), entry.getValue());
+		}
+		this.version = Iterables.get(Splitter.on('r').split(version), 0);
+		this.preconfigurationUrl = preconfigurationUrl;
+
+		this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory,
+				"runScriptOnNodeFactory");
+		this.socketTester = checkNotNull(socketTester, "socketTester");
+		this.socketTester.seconds(3L);
+		this.host = checkNotNull(host, "host");
+		this.providerSupplier = checkNotNull(providerSupplier,
+				"endpoint to virtualbox websrvd is needed");
+		this.hardcodedHostToHostNodeMetadata = hardcodedHostToHostNodeMetadata;
+	}
+
+	@PostConstruct
+	public void createCacheDirStructure() {
+		if (!new File(workingDir).exists()) {
+			new File(workingDir, "isos").mkdirs();
+		}
+	}
+
+	@Override
+	public synchronized Master get(Image key) throws ExecutionException {
+		// check if we have loaded this machine before
+		if (masters.containsKey(key.getId())) {
+			return masters.get(key.getId());
+		}
+		checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR),
+				"master image names cannot contain \""
+						+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
+		String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId();
+		IMachine masterMachine;
+		Master master;
+		// ready the preseed file server
+		PreseedCfgServer server = new PreseedCfgServer();
+		try {
+			// try and find a master machine in vbox
+			masterMachine = manager.get().getVBox().findMachine(vmName);
+			master = Master.builder().machine(masterMachine).build();
+		} catch (VBoxException e) {
+			if (machineNotFoundException(e)) {
+				// machine was not found try to build one from a yaml file
+				YamlImage currentImage = checkNotNull(imageMapping.get(key.getId()), "currentImage");
+				URI preseedServer;
+            try {
+               preseedServer = new URI(preconfigurationUrl);
+               if (!socketTester.apply(HostAndPort.fromParts(preseedServer.getHost(),
+                     preseedServer.getPort()))) {
+                  server.start(preconfigurationUrl, currentImage.preseed_cfg);
+               }
+            } catch (URISyntaxException e1) {
+               throw e;
+            }
+				
+				MasterSpec masterSpec = buildMasterSpecFromYaml(currentImage,
+						vmName);
+				
+				// create the master machine if it can't be found
+				masterMachine = masterCreatorAndInstaller.apply(masterSpec);
+				// build the master
+				master = Master.builder().machine(masterMachine)
+						.spec(masterSpec).build();
+			} else {
+				throw e;
+			}
+		} finally {
+			server.stop();
+		}
+
+		masters.put(key.getId(), master);
+		return master;
+	}
+
+	private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage,
+			String vmName) throws ExecutionException {
+		String guestAdditionsFileName = String.format(
+				"VBoxGuestAdditions_%s.iso", version);
+		String guestAdditionsIso = String.format("%s/%s", isosDir,
+				guestAdditionsFileName);
+		String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/"
+				+ version + "/" + guestAdditionsFileName;
+		if (!new File(guestAdditionsIso).exists()) {
+			getFilePathOrDownload(guestAdditionsUri, null);
+		}
+		// check if the iso is here, download if not
+		String localIsoUrl = checkNotNull(getFilePathOrDownload(currentImage.iso, currentImage.iso_md5), "distro iso");
+		String adminDisk = workingDir + File.separator + vmName + ".vdi";
+		HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk)
+				.autoDelete(true).controllerPort(0).deviceSlot(1).build();
+
+		StorageController ideController = StorageController.builder()
+				.name("IDE Controller").bus(StorageBus.IDE)
+				.attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk)
+				.attachISO(1, 0, guestAdditionsIso).build();
+
+		VmSpec vmSpecification = VmSpec.builder().id(currentImage.id)
+				.name(vmName).memoryMB(512).osTypeId("")
+				.controller(ideController).forceOverwrite(true)
+				.cleanUpMode(CleanupMode.Full).build();
+
+		NetworkAdapter networkAdapter = NetworkAdapter
+				.builder()
+				.networkAttachmentType(NetworkAttachmentType.NAT)
+				.tcpRedirectRule(providerSupplier.get().getHost(), MASTER_PORT,
+						"", 22).build();
+
+		NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
+				.builder().addNetworkAdapter(networkAdapter).slot(0L).build();
+
+		NetworkSpec networkSpec = NetworkSpec.builder()
+				.addNIC(networkInterfaceCard).build();
+
+		return MasterSpec
+				.builder()
+				.vm(vmSpecification)
+				.iso(IsoSpec
+						.builder()
+						.sourcePath(localIsoUrl)
+						.installationScript(
+								installationKeySequence.replace("HOSTNAME",
+										vmSpecification.getVmName())).build())
+				.network(networkSpec).build();
+	}
+
+	@Override
+	public synchronized Master getIfPresent(Object key) {
+		checkArgument(key instanceof Image,
+				"this cache is for entries who's keys are Images");
+		Image image = Image.class.cast(key);
+		if (masters.containsKey(image.getId())) {
+			return masters.get(image.getId());
+		}
+		return null;
+	}
+
+   private String getFilePathOrDownload(String httpUrl, String md5)
+         throws ExecutionException {
+      String fileName = httpUrl.substring(httpUrl.lastIndexOf('/') + 1,
+            httpUrl.length());
+      URI provider = providerSupplier.get();
+      if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(),
+            provider.getPort()))) {
+         throw new RuntimeException("could not connect to virtualbox");
       }
-      this.version = Iterables.get(Splitter.on('r').split(version), 0);
-      this.isoDownloader = isoDownloader;
-      this.preconfigurationUrl = preconfigurationUrl;
-   }
+      File file = new File(isosDir, fileName);
+      List<Statement> statements = Lists.newArrayList();
+      statements.add(Statements.saveHttpResponseTo(URI.create(httpUrl),
+            isosDir, fileName));
+      StatementList statementList = new StatementList(statements);
+      NodeMetadata hostNodeMetadata = hardcodedHostToHostNodeMetadata
+            .apply(host.get());
+      runScriptOnNodeFactory
+            .create(hostNodeMetadata, statementList, runAsRoot(false)).init()
+            .call();
 
-   @PostConstruct
-   public void createCacheDirStructure() {
-      if (!new File(workingDir).exists()) {
-         new File(workingDir, "isos").mkdirs();
+      ExecResponse response = runScriptOnNodeFactory
+            .create(
+                  hostNodeMetadata,
+                  Statements.exec("md5 " + isosDir + File.separator + fileName),
+                  runAsRoot(false)).init().call();
+      if (md5 != null) {
+         if (!Iterables.get(
+               Splitter.on("=").trimResults().split(response.getOutput()), 1)
+               .equals(md5))
+            return null;
       }
-   }
-
-   @Override
-   public synchronized Master get(Image key) throws ExecutionException {
-      // check if we have loaded this machine before
-      if (masters.containsKey(key.getId())) {
-         return masters.get(key.getId());
-      }
-
-      checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
-               + VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
-
-      String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId();
-
-      IMachine masterMachine;
-
-      Master master;
-
-      // ready the preseed file server
-      PreseedCfgServer server = new PreseedCfgServer();
-      try {
-         // try and find a master machine in vbox
-         masterMachine = manager.get().getVBox().findMachine(vmName);
-         master = Master.builder().machine(masterMachine).build();
-
-      } catch (VBoxException e) {
-         if (machineNotFoundException(e)) {
-            // machine was not found try to build one from a yaml file
-            YamlImage currentImage = imageMapping.get(key.getId());
-
-            checkNotNull(currentImage);
-
-            server.start(preconfigurationUrl, currentImage.preseed_cfg);
-
-            MasterSpec masterSpec = buildMasterSpecFromYaml(currentImage, vmName);
-
-            // create the master machine if it can't be found
-            masterMachine = masterCreatorAndInstaller.apply(masterSpec);
-
-            // build the master
-            master = Master.builder().machine(masterMachine).spec(masterSpec).build();
-         } else {
-            throw e;
-         }
-      } finally {
-         server.stop();
-      }
-
-      masters.put(key.getId(), master);
-      return master;
-   }
-
-   private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage, String vmName) throws ExecutionException {
-
-      String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version);
-      String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName);
-      String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName;
-      if (!new File(guestAdditionsIso).exists()) {
-         getFilePathOrDownload(guestAdditionsUri);
-      }
-      checkState(new File(guestAdditionsIso).exists(), "guest additions iso does not exist at: " + guestAdditionsIso);
-
-      // check if the iso is here, download if not
-      String localIsoUrl = getFilePathOrDownload(currentImage.iso);
-
-      String adminDisk = workingDir + File.separator + vmName + ".vdi";
-
-      HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1)
-               .build();
-
-      StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE)
-               .attachISO(0, 0, localIsoUrl).attachHardDisk(hardDisk).attachISO(1, 0, guestAdditionsIso).build();
-
-      VmSpec vmSpecification = VmSpec.builder().id(currentImage.id).name(vmName).memoryMB(512).osTypeId("")
-               .controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
-
-      NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
-               .tcpRedirectRule("127.0.0.1", MASTER_PORT, "", 22).build();
-
-      NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
-               .slot(0L).build();
-
-      NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
-
-      return MasterSpec
-               .builder()
-               .vm(vmSpecification)
-               .iso(IsoSpec.builder().sourcePath(localIsoUrl)
-                        .installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName()))
-                        .build()).network(networkSpec).build();
-   }
-
-   @Override
-   public synchronized Master getIfPresent(Object key) {
-      checkArgument(key instanceof Image, "this cache is for entries who's keys are Images");
-      Image image = Image.class.cast(key);
-      if (masters.containsKey(image.getId())) {
-         return masters.get(image.getId());
-      }
-      return null;
-   }
-
-   private String getFilePathOrDownload(String httpUrl) throws ExecutionException {
-      String fileName = httpUrl.substring(httpUrl.lastIndexOf('/') + 1, httpUrl.length());
-      File localFile = new File(isosDir, fileName);
-      if (!localFile.exists()) {
-         logger.debug("iso not found in cache, downloading: %s", httpUrl);
-         localFile = isoDownloader.apply(URI.create(httpUrl));
-      }
-      checkState(localFile.exists(), "iso file has not been downloaded: " + fileName);
-      return localFile.getAbsolutePath();
+      return file.getAbsolutePath();
    }
 
 }
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
index d417afb..e9f6f28 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/NodeCreator.java
@@ -22,10 +22,13 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_CREDENTIAL;
+import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_GUEST_IDENTITY;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_NAME_SEPARATOR;
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
 
+import java.net.URI;
 import java.util.List;
 
 import javax.inject.Inject;
@@ -39,7 +42,12 @@
 import org.jclouds.compute.domain.NodeMetadataBuilder;
 import org.jclouds.compute.options.RunScriptOptions;
 import org.jclouds.domain.LoginCredentials;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.location.Provider;
+import org.jclouds.rest.annotations.Credential;
+import org.jclouds.rest.annotations.Identity;
 import org.jclouds.scriptbuilder.domain.Statements;
+import org.jclouds.virtualbox.VirtualBoxApiMetadata;
 import org.jclouds.virtualbox.config.VirtualBoxComputeServiceContextModule;
 import org.jclouds.virtualbox.domain.CloneSpec;
 import org.jclouds.virtualbox.domain.Master;
@@ -63,8 +71,10 @@
 import org.virtualbox_4_1.VirtualBoxManager;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 
@@ -84,29 +94,36 @@
    private final MachineController machineController;
    private final Factory runScriptOnNodeFactory;
    private final Supplier<NodeMetadata> host;
-
-
+   private final Supplier<URI> providerSupplier;
+   private final String username;
+   private final String password;
+   private int ram = 512;
+   private final String guestIdentity = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_IDENTITY);
+   private final String guestCredential = VirtualBoxApiMetadata.defaultProperties().getProperty(VIRTUALBOX_GUEST_CREDENTIAL);
+   
    @Inject
    public NodeCreator(Supplier<VirtualBoxManager> manager, Function<CloneSpec, IMachine> cloner,  Factory runScriptOnNodeFactory,
+            MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController,
             Supplier<NodeMetadata> host,
-            MachineUtils machineUtils, RunScriptOnNode.Factory scriptRunnerFactory, MachineController machineController) {
+            @Provider Supplier<URI> providerSupplier,
+            @Nullable @Identity String identity,
+            @Nullable @Credential String credential) {
       this.manager = manager;
       this.cloner = cloner;
       this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
-      this.host = checkNotNull(host, "host");
-
       this.machineUtils = machineUtils;
       this.machineController = machineController;
+      this.host = checkNotNull(host, "host");
+      this.providerSupplier = checkNotNull(providerSupplier,
+            "endpoint to virtualbox websrvd is needed");
+      this.username = identity;
+      this.password = credential;
    }
 
    @Override
    public synchronized NodeAndInitialCredentials<IMachine> apply(NodeSpec nodeSpec) {
-
       checkNotNull(nodeSpec, "NodeSpec");
-
-      Master master = nodeSpec.getMaster();
-      checkNotNull(master, "Master");
-
+      Master master = checkNotNull(nodeSpec.getMaster(), "Master");
       if (master.getMachine().getCurrentSnapshot() != null) {
          ISession session;
          try {
@@ -119,40 +136,32 @@
          session.unlockMachine();
       }
       String masterNameWithoutPrefix = master.getMachine().getName().replace(VIRTUALBOX_IMAGE_PREFIX, "");
-
       String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix + VIRTUALBOX_NODE_NAME_SEPARATOR
                + nodeSpec.getTag() + VIRTUALBOX_NODE_NAME_SEPARATOR + nodeSpec.getName();
-
-      int ram = 512;
       if (nodeSpec.getTemplate() != null && nodeSpec.getTemplate().getHardware() != null
                && nodeSpec.getTemplate().getHardware().getRam() > 0) {
          ram = nodeSpec.getTemplate().getHardware().getRam();
       }
-      
-      VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram).cleanUpMode(CleanupMode.Full)
+      VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram)
+            .cleanUpMode(CleanupMode.Full)
                .forceOverwrite(true).build();
 
-      // CASE NAT + HOST-ONLY
-      NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
-               .build();
-      NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(natAdapter).slot(1L).build();
+      // case 'vbox host is localhost': NAT + HOST-ONLY
+      NetworkSpec networkSpec = createNetworkSpecWhenVboxIsLocalhost();
+      Optional<NetworkInterfaceCard> optionalNatIfaceCard = Iterables.tryFind(
+            networkSpec.getNetworkInterfaceCards(),
+            new Predicate<NetworkInterfaceCard>() {
 
-      NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.HostOnly)
-               .build();
-
-      // create new hostOnly interface if needed, otherwise use the one already there with dhcp enabled ...
-      String hostOnlyIfName = getHostOnlyIfOrCreate();
-      
-      NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(hostOnlyAdapter)
-               .addHostInterfaceName(hostOnlyIfName).slot(0L).build();
-
-      NetworkSpec networkSpec = createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard);
-
+               @Override
+               public boolean apply(NetworkInterfaceCard nic) {
+                  return nic.getNetworkAdapter().getNetworkAttachmentType()
+                        .equals(NetworkAttachmentType.NAT);
+               }
+            });
       CloneSpec cloneSpec = CloneSpec.builder().linked(true).master(master.getMachine()).network(networkSpec)
                .vm(cloneVmSpec).build();
 
       IMachine cloned = cloner.apply(cloneSpec);
-
       machineController.ensureMachineIsLaunched(cloneVmSpec.getVmName());
 
       // IMachineToNodeMetadata produces the final ip's but these need to be set before so we build a
@@ -160,42 +169,55 @@
       NodeMetadata partialNodeMetadata = buildPartialNodeMetadata(cloned);
 
       // see DeleteGShadowLock for a detailed explanation
-      machineUtils.runScriptOnNode(partialNodeMetadata, new DeleteGShadowLock(), RunScriptOptions.NONE);
+       machineUtils.runScriptOnNode(partialNodeMetadata, new DeleteGShadowLock(), RunScriptOptions.NONE);
 
-      // CASE NAT + HOST-ONLY
-      machineUtils.runScriptOnNode(partialNodeMetadata, new EnableNetworkInterface(natIfaceCard), RunScriptOptions.NONE);
-      
+      if(optionalNatIfaceCard.isPresent())
+         machineUtils.runScriptOnNode(partialNodeMetadata, new EnableNetworkInterface(optionalNatIfaceCard.get()), RunScriptOptions.NONE);
 
-      // TODO get credentials from somewhere else (they are also HC in
-      // IMachineToSshClient)
-      NodeAndInitialCredentials<IMachine> nodeAndInitialCredentials = new NodeAndInitialCredentials<IMachine>(cloned,
-               cloneName, LoginCredentials.builder().user("toor").password("password").authenticateSudo(true).build());
-
-      return nodeAndInitialCredentials;
+      return new NodeAndInitialCredentials<IMachine>(cloned,
+               cloneName, LoginCredentials.builder()
+               .user(guestIdentity)
+               .password(guestCredential)
+               .authenticateSudo(true)
+               .build());
    }
-   
+
    private NodeMetadata buildPartialNodeMetadata(IMachine clone) {
       NodeMetadataBuilder nodeMetadataBuilder = new NodeMetadataBuilder();
       nodeMetadataBuilder.id(clone.getName());
       nodeMetadataBuilder.status(VirtualBoxComputeServiceContextModule.toPortableNodeStatus.get(clone.getState()));
-      nodeMetadataBuilder.publicAddresses(ImmutableSet.of(machineUtils.getIpAddressFromHostOnlyNIC(clone.getName())));
-      
-      LoginCredentials loginCredentials = new LoginCredentials("toor", "password", null, true);
-      nodeMetadataBuilder.credentials(loginCredentials);
-      
+      nodeMetadataBuilder.publicAddresses(ImmutableSet.of(machineUtils.getIpAddressFromFirstNIC(clone.getName())));
+      LoginCredentials loginCredentials = new LoginCredentials(guestIdentity, guestCredential, null, true);
+      nodeMetadataBuilder.credentials(loginCredentials);    
       return  nodeMetadataBuilder.build();
    }
 
-   private NetworkSpec createNetworkSpecForHostOnlyNATNICs(NetworkInterfaceCard natIfaceCard,
-            NetworkInterfaceCard hostOnlyIfaceCard) {
-      return NetworkSpec.builder().addNIC(natIfaceCard).addNIC(hostOnlyIfaceCard).build();
+   private NetworkSpec createNetworkSpecWhenVboxIsLocalhost() {
+      NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
+            .build();      
+      NetworkInterfaceCard natIfaceCard = NetworkInterfaceCard.builder()
+            .addNetworkAdapter(natAdapter)
+            .slot(1L)
+            .build();
+      NetworkAdapter hostOnlyAdapter = NetworkAdapter.builder()
+            .networkAttachmentType(NetworkAttachmentType.HostOnly)
+               .build();
+      // create new hostOnly interface if needed, otherwise use the one already there with dhcp enabled ...
+      String hostOnlyIfName = getHostOnlyIfOrCreate();
+      NetworkInterfaceCard hostOnlyIfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(hostOnlyAdapter)
+               .addHostInterfaceName(hostOnlyIfName).slot(0L).build();      
+      return createNetworkSpecForHostOnlyNATNICs(natIfaceCard, hostOnlyIfaceCard);
    }
    
-   /**
-    * @return
-    */
+   private NetworkSpec createNetworkSpecForHostOnlyNATNICs(NetworkInterfaceCard natIfaceCard,
+            NetworkInterfaceCard hostOnlyIfaceCard) {
+      return NetworkSpec.builder()
+            .addNIC(natIfaceCard)
+            .addNIC(hostOnlyIfaceCard)
+            .build();
+   }
+
    private String getHostOnlyIfOrCreate() {     
-      
       IHostNetworkInterface availableHostInterfaceIf = returnExistingHostNetworkInterfaceWithDHCPenabledOrNull(manager
                .get().getVBox().getHost().getNetworkInterfaces());
       if (availableHostInterfaceIf==null) {
@@ -205,7 +227,6 @@
       } else {
          return availableHostInterfaceIf.getName();
       }
-      
    }
 
    private void assignDHCPtoHostOnlyInterface(final String hostOnlyIfName) {
@@ -225,25 +246,21 @@
       String dhcpNetmask = "255.255.255.0";
       String dhcpLowerIp = hostOnlyIfIpAddress.substring(0, hostOnlyIfIpAddress.lastIndexOf(".")) + ".2";
       String dhcpUpperIp = hostOnlyIfIpAddress.substring(0, hostOnlyIfIpAddress.lastIndexOf(".")) + ".253";
-      
+      NodeMetadata hostNodeMetadata = getHostNodeMetadata();
+
       ExecResponse response = runScriptOnNodeFactory
-               .create(host.get(),
+               .create(hostNodeMetadata,
                         Statements.exec(String
                                  .format("VBoxManage dhcpserver add --ifname %s --ip %s --netmask %s --lowerip %s --upperip %s --enable",
                                           hostOnlyIfName, dhcpIpAddress, dhcpNetmask, dhcpLowerIp, dhcpUpperIp)), runAsRoot(false).wrapInInitScript(false)).init().call();
       checkState(response.getExitStatus()==0);
-      /*
-      runScriptOnNodeFactory
-               .create(host.get(),
-                        Statements.exec(String.format("VBoxManage hostonlyif ipconfig %s --ip %s",
-                                 hostOnlyIfName, hostOnlyIfIpAddress)), runAsRoot(false).wrapInInitScript(false)).init().call();
-      */
    }
 
    private String createHostOnlyIf() {
       final String hostOnlyIfName;
+      NodeMetadata hostNodeMetadata = getHostNodeMetadata();
       ExecResponse createHostOnlyResponse = runScriptOnNodeFactory
-               .create(host.get(), Statements.exec("VBoxManage hostonlyif create"),
+               .create(hostNodeMetadata, Statements.exec("VBoxManage hostonlyif create"),
                         runAsRoot(false).wrapInInitScript(false)).init().call();
       String output = createHostOnlyResponse.getOutput();
       checkState(createHostOnlyResponse.getExitStatus()==0);
@@ -252,6 +269,16 @@
       return hostOnlyIfName;
    }
 
+   private NodeMetadata getHostNodeMetadata() {
+      NodeMetadata hostNodeMetadata = NodeMetadataBuilder
+            .fromNodeMetadata(host.get())
+            .credentials(LoginCredentials.builder().user(username).password(password).build())
+            .publicAddresses(
+                  ImmutableList.of(providerSupplier.get().getHost()))
+            .build();
+      return hostNodeMetadata;
+   }
+
    private IHostNetworkInterface returnExistingHostNetworkInterfaceWithDHCPenabledOrNull(Iterable<IHostNetworkInterface> availableNetworkInterfaces) {
       checkNotNull(availableNetworkInterfaces);
       return Iterables.getFirst(filterAvailableNetworkInterfaceByHostOnlyAndDHCPenabled(availableNetworkInterfaces), null);
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
index 4b5eeba..b9d21b7 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunning.java
@@ -24,22 +24,29 @@
 import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
 
 import java.net.URI;
+import java.util.List;
 
+import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.jclouds.compute.callables.RunScriptOnNode.Factory;
+import org.jclouds.compute.domain.ExecResponse;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.location.Provider;
 import org.jclouds.logging.Logger;
+import org.jclouds.scriptbuilder.domain.Statement;
+import org.jclouds.scriptbuilder.domain.StatementList;
 import org.jclouds.scriptbuilder.domain.Statements;
+import org.jclouds.virtualbox.functions.HardcodedHostToHostNodeMetadata;
 import org.jclouds.virtualbox.predicates.RetryIfSocketNotYetOpen;
 import org.virtualbox_4_1.SessionState;
 import org.virtualbox_4_1.VirtualBoxManager;
 
+import com.beust.jcommander.internal.Lists;
 import com.google.common.base.Function;
 import com.google.common.base.Supplier;
 import com.google.common.net.HostAndPort;
@@ -57,43 +64,74 @@
    private final Supplier<URI> providerSupplier;
    private final Function<Supplier<NodeMetadata>, VirtualBoxManager> managerForNode;
    private transient VirtualBoxManager manager;
+   private final HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata;
 
    // the functions and suppliers here are to ensure we don't do heavy i/o in injection
    @Inject
    public StartVBoxIfNotAlreadyRunning(Function<Supplier<NodeMetadata>, VirtualBoxManager> managerForNode,
             Factory runScriptOnNodeFactory, RetryIfSocketNotYetOpen socketTester, Supplier<NodeMetadata> host,
-            @Provider Supplier<URI> providerSupplier) {
+            @Provider Supplier<URI> providerSupplier,
+            HardcodedHostToHostNodeMetadata hardcodedHostToHostNodeMetadata) {
       this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
       this.socketTester = checkNotNull(socketTester, "socketTester");
       this.socketTester.seconds(3L);
       this.host = checkNotNull(host, "host");
       this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed");
       this.managerForNode = checkNotNull(managerForNode, "managerForNode");
-      start();
+      this.hardcodedHostToHostNodeMetadata = hardcodedHostToHostNodeMetadata;
    }
 
+   @PostConstruct
    public synchronized void start() {
       URI provider = providerSupplier.get();
-      if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(), provider.getPort()))) {
-         logger.debug("disabling password access");
-         runScriptOnNodeFactory.create(host.get(), Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
-                  runAsRoot(false).wrapInInitScript(false)).init().call();
-         logger.debug(">> starting vboxwebsrv");
-         String vboxwebsrv = "vboxwebsrv -t 10000 -v -b";
-         runScriptOnNodeFactory.create(host.get(), Statements.exec(vboxwebsrv),
-                  runAsRoot(false).wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv")).init().call();
-         
-         if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(), provider.getPort()))){
-            throw new RuntimeException("could not connect to virtualbox");
-         }
+      NodeMetadata hostNodeMetadata = hardcodedHostToHostNodeMetadata.apply(host.get());
+      // kill previously started vboxwebsrv (possibly dirty session)
+      List<Statement> statements =      Lists.newArrayList();
+      statements.add(Statements.findPid("vboxwebsrv"));
+      statements.add(Statements.kill());
+      StatementList statementList = new StatementList(statements);
+      
+      if (socketTester.apply(HostAndPort.fromParts(provider.getHost(),
+            provider.getPort()))) {
+         logger.debug(String.format("shutting down previously started vboxwewbsrv at %s", provider));
+         ExecResponse execResponse = runScriptOnNodeFactory
+               .create(hostNodeMetadata, statementList, runAsRoot(false))
+               .init().call();
+         if(execResponse.getExitStatus()!=0)
+            throw new RuntimeException("Cannot execute jclouds");
       }
+      
+      logger.debug("disabling password access");
+      runScriptOnNodeFactory
+            .create(
+                  hostNodeMetadata,
+                  Statements
+                        .exec("VBoxManage setproperty websrvauthlibrary null"),
+                  runAsRoot(false).wrapInInitScript(false)).init().call();
+      logger.debug(">> starting vboxwebsrv");
+      String vboxwebsrv = "vboxwebsrv -t0 -v -b -H "
+            + providerSupplier.get().getHost();
+      runScriptOnNodeFactory
+            .create(
+                  hostNodeMetadata,
+                  Statements.exec(vboxwebsrv),
+                  runAsRoot(false).wrapInInitScript(false)
+                        .blockOnComplete(false).nameTask("vboxwebsrv")).init()
+            .call();
+
+      if (!socketTester.apply(HostAndPort.fromParts(provider.getHost(),
+            provider.getPort()))) {
+         throw new RuntimeException("could not connect to virtualbox");
+      }
+
       manager = managerForNode.apply(host);
       manager.connect(provider.toASCIIString(), "", "");
       if (logger.isDebugEnabled())
          if (manager.getSessionObject().getState() != SessionState.Unlocked)
-            logger.warn("manager is not in unlocked state " + manager.getSessionObject().getState());
+            logger.warn("manager is not in unlocked state "
+                  + manager.getSessionObject().getState());
    }
-
+   
    @Override
    public VirtualBoxManager get() {
       checkState(manager != null, "start not called");
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/EnableNetworkInterface.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/EnableNetworkInterface.java
index 224fd2f..59be70d 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/EnableNetworkInterface.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/statements/EnableNetworkInterface.java
@@ -63,9 +63,6 @@
    }
 
    private List<Statement> getStatements(String iface) {
-      /*
-       * auto eth0
-       */
       List<Statement> statements = Lists.newArrayList();
       statements.add(exec(String.format("echo auto %s >> /etc/network/interfaces", iface))); //
       statements.add(exec(String.format("echo iface %s inet dhcp >> /etc/network/interfaces", iface))); //
diff --git a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java
index 11e6279..c0d2370 100644
--- a/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java
+++ b/labs/virtualbox/src/main/java/org/jclouds/virtualbox/util/MachineUtils.java
@@ -21,6 +21,7 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 
+import java.util.concurrent.ExecutionException;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -37,6 +38,7 @@
 import org.jclouds.logging.Logger;
 import org.jclouds.scriptbuilder.domain.Statement;
 import org.jclouds.util.Throwables2;
+import org.jclouds.virtualbox.functions.IpAddressesLoadingCache;
 import org.virtualbox_4_1.IMachine;
 import org.virtualbox_4_1.ISession;
 import org.virtualbox_4_1.LockType;
@@ -69,12 +71,14 @@
 
    private final Supplier<VirtualBoxManager> manager;
    private final Factory scriptRunner;
+   private final IpAddressesLoadingCache ipAddressesLoadingCache;
 
    @Inject
-   public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner) {
-      super();
+   public MachineUtils(Supplier<VirtualBoxManager> manager, RunScriptOnNode.Factory scriptRunner,
+         IpAddressesLoadingCache ipAddressesLoadingCache) {
       this.manager = manager;
       this.scriptRunner = scriptRunner;
+      this.ipAddressesLoadingCache = ipAddressesLoadingCache;
    }
 
    public ListenableFuture<ExecResponse> runScriptOnNode(NodeMetadata metadata, Statement statement,
@@ -207,9 +211,18 @@
    private ISession lockSession(String machineId, LockType type, int retries) {
       int count = 0;
       ISession session;
+      IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
+
+      try {
+      session = manager.get().openMachineSession(immutableMachine);
+      if (session.getState().equals(SessionState.Locked)) 
+         return checkNotNull(session, "session"); 
+      } catch (Exception e) {
+         logger.debug("machine %s is not locked). Error: %s", immutableMachine.getName(), e.getMessage());
+      }
+      
       while (true) {
          try {
-            IMachine immutableMachine = manager.get().getVBox().findMachine(machineId);
             session = manager.get().getSessionObject();
             immutableMachine.lockMachine(session, type);
             break;
@@ -219,13 +232,13 @@
                return null;
             }
             count++;
-            logger.warn(e, "Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage());
+            logger.debug("Could not lock machine (try %d of %d). Error: %s", count, retries, e.getMessage());
             if (count == retries) {
                throw new RuntimeException(String.format("error locking %s with %s lock: %s", machineId, type,
                         e.getMessage()), e);
             }
             try {
-               Thread.sleep(1000L);
+               Thread.sleep(count * 1000L);
             } catch (InterruptedException e1) {
             }
          }
@@ -265,70 +278,24 @@
                || e.getMessage().contains("Could not find a registered machine with UUID {");
    }
    
-   public String getIpAddressFromBridgedNIC(String machineName) {
-      String ip = "";
-      int attempt = 0;
-      while (!isIpv4(ip) && attempt < 10) {
-         ip = this.lockSessionOnMachineAndApply(machineName, LockType.Shared, new Function<ISession, String>() {
-            @Override
-            public String apply(ISession session) {
-               String ip = session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
-               return ip;
-            }
-         });
-         attempt++;
-         long sleepTime = 1000 * attempt;
-         logger.debug("Instance %s is still not ready. Attempt n:%d. Sleeping for %d millisec", machineName, attempt,
-                  sleepTime);
-         try {
-            Thread.sleep(sleepTime);
-         } catch (InterruptedException e) {
-            Throwables.propagate(e);
-         }
+   public String getIpAddressFromFirstNIC(String machineName) {
+      try {
+         return ipAddressesLoadingCache.get(machineName);
+      } catch (ExecutionException e) {
+         logger.error("Problem in using the ipAddressCache", e.getCause());
+         throw Throwables.propagate(e);
       }
-      return ip;
    }
+ 
 
-   private boolean isIpv4(String s) {
-      Pattern pattern = Pattern.compile(this.IP_V4_ADDRESS_PATTERN);
+   public static boolean isIpv4(String s) {
+      String IP_V4_ADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+            + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+            + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
+      Pattern pattern = Pattern.compile(IP_V4_ADDRESS_PATTERN);
       Matcher matcher = pattern.matcher(s);
       return matcher.matches();
    }
 
-   public String getIpAddressFromHostOnlyNIC(String machineName) {
-      // TODO using a caching mechanism to avoid to call every time this vboxmanage api call
-      String currentIp = "", previousIp = "1.1.1.1";
-      int attempt = 0, count = 0;
-      while(count < 5) { 
-         currentIp = "";
-         attempt = 0;
-         while (!isIpv4(currentIp) &&  attempt < 5) {
-            currentIp = this.lockSessionOnMachineAndApply(machineName, LockType.Shared, new Function<ISession, String>() {
-               @Override
-               public String apply(ISession session) {
-                  return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
-               }
-            });
-            attempt++;
-         }
-         if(previousIp.equals(currentIp)) {
-            count++;
-            delayer(500l * (count + 1));
-         } else {
-            count = 0;
-            delayer(5000l);
-         }
-         previousIp = currentIp;
-      }
-      return currentIp;
-   }
-
-   private void delayer(long millisec) {
-      try {
-         Thread.sleep(millisec);
-      } catch (InterruptedException e) {
-         Throwables.propagate(e);
-      }
-   }   
 
 }
diff --git a/labs/virtualbox/src/main/resources/default-images.yaml b/labs/virtualbox/src/main/resources/default-images.yaml
index 84380c2..c9ed61f 100644
--- a/labs/virtualbox/src/main/resources/default-images.yaml
+++ b/labs/virtualbox/src/main/resources/default-images.yaml
@@ -15,7 +15,7 @@
                 fb=false debconf/frontend=noninteractive 
                 keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false 
                 initrd=/install/initrd.gz -- <Enter>
-      preseed_cfg: |                
+      preseed_cfg: |
                       ## Options to set on the command line
                       d-i debian-installer/locale string en_US.utf8
                       d-i console-setup/ask_detect boolean false
@@ -132,4 +132,91 @@
                       d-i pkgsel/update-policy select none
                       # debconf-get-selections --install
                       #Use mirror
+                      choose-mirror-bin mirror/http/proxy string
+    - id: ubuntu-12.04.1-amd64
+      name: ubuntu-12.04.1-server-amd64
+      description: ubuntu 12.04.1 server (amd64)
+      os_arch: amd64
+      os_family: ubuntu
+      os_description: ubuntu
+      os_version: 12.04.1
+      os_64bit: true
+      iso: http://releases.ubuntu.com/12.04/ubuntu-12.04.1-server-amd64.iso
+      username: toor
+      credential: $user
+      keystroke_sequence: |
+                <Esc><Esc><Enter> 
+                /install/vmlinuz noapic preseed/url=http://10.0.2.2:8080/src/test/resources/preseed.cfg 
+                debian-installer=en_US auto locale=en_US kbd-chooser/method=us 
+                hostname=vmName 
+                fb=false debconf/frontend=noninteractive 
+                keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false 
+                initrd=/install/initrd.gz -- <Enter>
+      preseed_cfg: |
+                      ## Options to set on the command line
+                      d-i debian-installer/locale string en_US.utf8
+                      d-i console-setup/ask_detect boolean false
+                      d-i console-setup/layout string USA
+                      #d-i netcfg/get_hostname string dummy
+                      d-i netcfg/get_hostname string unassigned-hostname
+                      d-i netcfg/get_domain string unassigned-domain
+                      # Continue without a default route
+                      # Not working , specify a dummy in the DHCP
+                      #d-i netcfg/no_default_route boolean
+                      d-i time/zone string UTC
+                      d-i clock-setup/utc-auto boolean true
+                      d-i clock-setup/utc boolean true
+                      d-i kbd-chooser/method select American English
+                      d-i netcfg/wireless_wep string
+                      d-i base-installer/kernel/override-image string linux-server
+                      #d-i base-installer/kernel/override-image string linux-image-2.6.32-21-generic
+                      # Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive
+                      d-i debconf debconf/frontend select Noninteractive
+                      d-i pkgsel/install-language-support boolean false
+                      tasksel tasksel/first multiselect standard, ubuntu-server
+                      #d-i partman-auto/method string regular
+                      d-i partman-auto/method string lvm
+                      #d-i partman-auto/purge_lvm_from_device boolean true
+                      d-i partman-lvm/confirm boolean true
+                      d-i partman-lvm/device_remove_lvm boolean true
+                      d-i partman-auto/choose_recipe select atomic
+                      d-i partman/confirm_write_new_label boolean true
+                      d-i partman/confirm_nooverwrite boolean true
+                      d-i partman/choose_partition select finish
+                      d-i partman/confirm boolean true
+                      #http://ubuntu-virginia.ubuntuforums.org/showthread.php?p=9626883
+                      #Message: "write the changes to disk and configure lvm preseed"
+                      #http://serverfault.com/questions/189328/ubuntu-kickstart-installation-using-lvm-waits-for-input
+                      #preseed partman-lvm/confirm_nooverwrite boolean true
+                      # Write the changes to disks and configure LVM?
+                      d-i partman-lvm/confirm boolean true
+                      d-i partman-lvm/confirm_nooverwrite boolean true
+                      d-i partman-auto-lvm/guided_size string max
+                      ## Default user, we can get away with a recipe to change this
+                      d-i passwd/user-fullname string toor
+                      d-i passwd/username string toor
+                      d-i passwd/user-password password password
+                      d-i passwd/user-password-again password password
+                      d-i user-setup/encrypt-home boolean false
+                      d-i user-setup/allow-password-weak boolean true
+                      ## minimum is ssh and ntp
+                      # Individual additional packages to install
+                      d-i pkgsel/include string openssh-server ntp
+                      # Whether to upgrade packages after debootstrap.
+                      # Allowed values: none, safe-upgrade, full-upgrade
+                      d-i pkgsel/upgrade select full-upgrade
+                      d-i grub-installer/only_debian boolean true
+                      d-i grub-installer/with_other_os boolean true
+                      d-i finish-install/reboot_in_progress note
+                      #For the update
+                      d-i pkgsel/update-policy select none
+                      # debconf-get-selections --install
+                      #Use mirror
+                      #d-i apt-setup/use_mirror boolean true
+                      #d-i mirror/country string manual
+                      #choose-mirror-bin mirror/protocol string http
+                      #choose-mirror-bin mirror/http/hostname string 192.168.4.150
+                      #choose-mirror-bin mirror/http/directory string /ubuntu
+                      #choose-mirror-bin mirror/suite select maverick
+                      #d-i debian-installer/allow_unauthenticated string true
                       choose-mirror-bin mirror/http/proxy string
\ No newline at end of file
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
index b2c2c45..4dbe578 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/BaseVirtualBoxClientLiveTest.java
@@ -119,7 +119,7 @@
    protected LoadingCache<Image, Master> mastersCache;
 
    private final ExecutorService singleThreadExec = MoreExecutors.sameThreadExecutor();
-   private String masterVmName;
+   private String masterName;
    
 
    @Override
@@ -133,13 +133,13 @@
    public void setupContext() {
       super.setupContext();
       view.utils().injector().injectMembers(this);
-
+      
       // try and get a master from the cache, this will initialize the config/download isos and
       // prepare everything IF a master is not available, subsequent calls should be pretty fast
       Template template = view.getComputeService().templateBuilder().build();
       checkNotNull(mastersCache.apply(template.getImage()));
 
-      masterVmName = VIRTUALBOX_IMAGE_PREFIX + template.getImage().getId();
+      masterName = VIRTUALBOX_IMAGE_PREFIX + template.getImage().getId();
       isosDir = workingDir + File.separator + "isos";
 
       hostVersion = Iterables.get(Splitter.on('r').split(view.utils().injector().getInstance(Key.get(String.class, BuildVersion.class))), 0);
@@ -173,8 +173,6 @@
    }
 
    public MasterSpec getMasterSpecForTest() {
-      String masterName = "jclouds-image-0x0-" + template.getImageId();
-
       StorageController ideController = StorageController
                .builder()
                .name("IDE Controller")
@@ -220,7 +218,7 @@
    protected void destroyMaster() {
       if (System.getProperty(DONT_DESTROY_MASTER) == null
                || !Boolean.parseBoolean(System.getProperty(DONT_DESTROY_MASTER))) {
-         undoVm(masterVmName);
+         undoVm(masterName);
       }
    }
 
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/PreseedCfgServerTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/PreseedCfgServerTest.java
index 28c6001..ad71c22 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/PreseedCfgServerTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/PreseedCfgServerTest.java
@@ -20,7 +20,6 @@
 
 import static org.testng.Assert.assertEquals;
 
-import java.io.File;
 import java.net.URI;
 import java.net.URL;
 import java.util.Map;
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
index cf3969d..7cdee2d 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxComputeServiceAdapterLiveTest.java
@@ -51,7 +51,7 @@
    @Test
    public void testCreatedNodeHasExpectedNameAndWeCanConnectViaSsh() {
       String group = "foo";
-      String name = "foo-ef4";
+      String name = "foo-ef9";
       Template template = view.getComputeService().templateBuilder().build();
       machine = adapter.createNodeWithGroupEncodedIntoName(group, name, template);
       assertTrue(machine.getNode().getName().contains(group));
@@ -60,7 +60,7 @@
       doConnectViaSsh(machine.getNode(), prioritizeCredentialsFromTemplate.apply(template, machine.getCredentials()));
    }
 
-   protected void doConnectViaSsh(IMachine machine, LoginCredentials creds) {
+   protected void doConnectViaSsh(IMachine machine, LoginCredentials creds) {      
       SshClient ssh = view.utils().injector().getInstance(IMachineToSshClient.class).apply(machine);
       try {
          ssh.connect();
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java
index b2929b4..fa5e67a 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/VirtualBoxExperimentLiveTest.java
@@ -36,7 +36,6 @@
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.logging.Logger;
 import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
-import org.jclouds.scriptbuilder.statements.login.AdminAccess;
 import org.jclouds.ssh.SshClient;
 import org.jclouds.sshj.config.SshjSshClientModule;
 import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
@@ -69,10 +68,10 @@
 
    @Test
    public void testLaunchCluster() throws RunNodesException {
-      int numNodes = 2;
+      int numNodes = 3;
       final String clusterName = "test-launch-cluster";
       Set<? extends NodeMetadata> nodes = context.getComputeService().createNodesInGroup(clusterName, numNodes,
-               TemplateOptions.Builder.runScript(AdminAccess.standard()));
+               TemplateOptions.Builder.overrideLoginUser("toor")); //TODO runScript(AdminAccess.standard()));
       assertEquals(numNodes, nodes.size(), "wrong number of nodes");
       for (NodeMetadata node : nodes) {
          assertTrue(node.getGroup().equals("test-launch-cluster"));
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/extensions/VirtualBoxImageExtensionLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/extensions/VirtualBoxImageExtensionLiveTest.java
index 31a416b..575a182 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/extensions/VirtualBoxImageExtensionLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/compute/extensions/VirtualBoxImageExtensionLiveTest.java
@@ -19,6 +19,9 @@
 
 package org.jclouds.virtualbox.compute.extensions;
 
+import java.util.concurrent.ExecutionException;
+
+import org.jclouds.compute.RunNodesException;
 import org.jclouds.compute.extensions.internal.BaseImageExtensionLiveTest;
 import org.jclouds.sshj.config.SshjSshClientModule;
 import org.testng.annotations.Test;
@@ -28,6 +31,22 @@
 @Test(groups = "live", singleThreaded = true, testName = "VirtualBoxImageExtensionLiveTest")
 public class VirtualBoxImageExtensionLiveTest extends BaseImageExtensionLiveTest {
 
+   @Override
+   public void testDeleteImage() {
+      // TODO
+   }
+
+   @Override
+   public void testCreateImage() throws RunNodesException,
+         InterruptedException, ExecutionException {
+      // TODO
+   }
+
+   @Override
+   public void testSpawnNodeFromImage() throws RunNodesException {
+      // TODO
+   }
+
    public VirtualBoxImageExtensionLiveTest() {
       provider = "virtualbox";
    }
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
index c557620..bd25a24 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/CreateAndInstallVmLiveTest.java
@@ -24,14 +24,18 @@
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
 import static org.testng.Assert.assertTrue;
 
+import java.net.URI;
 import java.util.Map;
 
+import javax.inject.Inject;
+
 import org.jclouds.compute.config.BaseComputeServiceContextModule;
 import org.jclouds.compute.domain.OsFamily;
 import org.jclouds.compute.reference.ComputeServiceConstants;
 import org.jclouds.config.ValueOfConfigurationKeyOrNull;
 import org.jclouds.json.Json;
 import org.jclouds.json.config.GsonModule;
+import org.jclouds.location.Provider;
 import org.jclouds.ssh.SshClient;
 import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
 import org.jclouds.virtualbox.domain.CloneSpec;
@@ -49,13 +53,13 @@
 import org.testng.annotations.Test;
 import org.virtualbox_4_1.CleanupMode;
 import org.virtualbox_4_1.IMachine;
-import org.virtualbox_4_1.ISession;
 import org.virtualbox_4_1.NetworkAttachmentType;
 import org.virtualbox_4_1.StorageBus;
 
 import com.google.common.base.CaseFormat;
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -76,44 +80,11 @@
    
    private MasterSpec machineSpec;
    private String instanceName;
-
-   /*
-   @Override
-   @BeforeClass(groups = "live")
-   public void setupClient() {
-      super.setupClient();
-      this.vmName = VIRTUALBOX_IMAGE_PREFIX
-               + CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, getClass().getSimpleName());
-
-      HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk(vmName)).autoDelete(true).controllerPort(0)
-               .deviceSlot(1).build();
-      StorageController ideController = StorageController.builder().name("IDE Controller").bus(StorageBus.IDE)
-               .attachISO(0, 0, operatingSystemIso).attachHardDisk(hardDisk).attachISO(1, 1, guestAdditionsIso).build();
-      vmSpecification = VmSpec.builder().id(vmName).name(vmName).memoryMB(512).osTypeId("").controller(ideController)
-               .forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
-
-      injector = context.utils().injector();
-      Function<String, String> configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class);
-
-      NetworkAdapter natAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
-               .tcpRedirectRule("127.0.0.1", 2222, "", 22).build();
-
-      NetworkInterfaceCard networkInterfaceCard1 = NetworkInterfaceCard.builder().slot(0l)
-               .addNetworkAdapter(natAdapter).build();
-
-      NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard1).build();
-
-      masterSpec = MasterSpec
-               .builder()
-               .vm(vmSpecification)
-               .iso(IsoSpec
-                        .builder()
-                        .sourcePath(operatingSystemIso)
-                        .installationScript(
-                                 configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME",
-                                          vmSpecification.getVmName())).build()).network(networkSpec).build();
-   }*/
    
+   @Inject 
+   @Provider
+   protected Supplier<URI> providerSupplier;
+
    @Override
    @BeforeClass(groups = "live")
    public void setupContext() {
@@ -142,11 +113,10 @@
                         configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME",
                                  instanceVmSpec.getVmName())).build();
 
-      NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
-               .tcpRedirectRule("127.0.0.1", 2222, "", 22).build();
-      NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
+      NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.HostOnly)
                .build();
-
+      NetworkInterfaceCard networkInterfaceCard =  NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
+            .addHostInterfaceName("vboxnet0").slot(0L).build();
       NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
       machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec).network(networkSpec).build();
    }
@@ -164,12 +134,7 @@
          checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
                   machine.getName());
 
-         String version = machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
-            @Override
-            public String apply(ISession session) {
-               return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
-            }
-         });
+         String version = machine.getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
          
          assertTrue(version != null && !version.isEmpty());
       } finally {
@@ -193,7 +158,6 @@
          Injector injector = view.utils().injector();
          return injector.getInstance(CreateAndInstallVm.class).apply(masterSpecForTest);
       } catch (IllegalStateException e) {
-         // already created
          return manager.get().getVBox().findMachine(masterSpecForTest.getVmSpec().getVmId());
       }
    }
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
index b3b31da..22016b2 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/functions/admin/StartVBoxIfNotAlreadyRunningLiveTest.java
@@ -64,7 +64,7 @@
       replay(manager, runScriptOnNodeFactory, client);
 
       new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client,
-               Suppliers.ofInstance(host), Suppliers.ofInstance(provider)).start();
+               Suppliers.ofInstance(host), Suppliers.ofInstance(provider), null).start();
 
       verify(manager, runScriptOnNodeFactory, client);
 
@@ -84,26 +84,26 @@
       
       expect(client.seconds(3)).andReturn(client);
       expect(client.apply(HostAndPort.fromParts(provider.getHost(), provider.getPort()))).andReturn(false).once().andReturn(true).once();
-      expect(
-               runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
+      expect(runScriptOnNodeFactory.create(host, 
+            Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
                         runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode);
       expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
       expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
       
-      expect(
-               runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false)
-                        .wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn(
-               runScriptOnNode);
+      expect(runScriptOnNodeFactory.create(host, 
+                     Statements.exec("vboxwebsrv -t 10000 -v -b -H localhost"), runAsRoot(false)
+                        .wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv")))
+                        .andReturn(runScriptOnNode);
       
       expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
       expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
-      
       manager.connect(provider.toASCIIString(), "", "");
+      expectLastCall().anyTimes();
 
       replay(manager, runScriptOnNodeFactory, runScriptOnNode, client);
       new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client,
-               Suppliers.ofInstance(host), Suppliers.ofInstance(provider));
+               Suppliers.ofInstance(host), Suppliers.ofInstance(provider), null);
+      
       verify(manager, runScriptOnNodeFactory, runScriptOnNode, client);
-
    }
 }
\ No newline at end of file
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java
index 8c79df1..b21ce39 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/predicates/GuestAdditionsInstallerLiveTest.java
@@ -24,9 +24,6 @@
 import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
 import static org.testng.Assert.assertTrue;
 
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 import org.jclouds.config.ValueOfConfigurationKeyOrNull;
 import org.jclouds.ssh.SshClient;
 import org.jclouds.virtualbox.BaseVirtualBoxClientLiveTest;
@@ -42,11 +39,12 @@
 import org.jclouds.virtualbox.functions.CloneAndRegisterMachineFromIMachineIfNotAlreadyExists;
 import org.jclouds.virtualbox.functions.CreateAndInstallVm;
 import org.jclouds.virtualbox.functions.IMachineToSshClient;
+import org.jclouds.virtualbox.functions.IpAddressesLoadingCache;
+import org.jclouds.virtualbox.util.MachineUtils;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import org.virtualbox_4_1.CleanupMode;
 import org.virtualbox_4_1.IMachine;
-import org.virtualbox_4_1.ISession;
 import org.virtualbox_4_1.NetworkAttachmentType;
 import org.virtualbox_4_1.StorageBus;
 
@@ -67,6 +65,7 @@
    private Predicate<SshClient> sshResponds;
 
    private MasterSpec machineSpec;
+   private IpAddressesLoadingCache ipAddressesLoadingCache;
 
    @Override
    @BeforeClass(groups = "live")
@@ -118,21 +117,10 @@
          sshResponds = injector.getInstance(SshResponds.class);
          checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
                   machine.getName());
+         ipAddressesLoadingCache = injector.getInstance(IpAddressesLoadingCache.class);
+         
+         assertTrue(MachineUtils.isIpv4(ipAddressesLoadingCache.apply(machine.getName())));
 
-         assertTrue(machineUtils.sharedLockMachineAndApplyToSession(machine.getName(),
-                  new Function<ISession, Boolean>() {
-                     @Override
-                     public Boolean apply(ISession session) {
-                        String s = session.getMachine().getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP");
-                        return isIpv4(s);
-                     }
-
-                     private boolean isIpv4(String s) {
-                        Pattern pattern = Pattern.compile(machineUtils.IP_V4_ADDRESS_PATTERN);
-                        Matcher matcher = pattern.matcher(s);
-                        return matcher.matches();
-                     }
-                  }));
       } finally {
          for (String vmNameOrId : ImmutableSet.of(machine.getName())) {
             machineController.ensureMachineHasPowerDown(vmNameOrId);
diff --git a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/util/MachineControllerLiveTest.java b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/util/MachineControllerLiveTest.java
index 2291d62..6b15823 100644
--- a/labs/virtualbox/src/test/java/org/jclouds/virtualbox/util/MachineControllerLiveTest.java
+++ b/labs/virtualbox/src/test/java/org/jclouds/virtualbox/util/MachineControllerLiveTest.java
@@ -77,21 +77,25 @@
                .cleanUpMode(CleanupMode.Full).controller(ideController).forceOverwrite(true).build();
 
       Injector injector = view.utils().injector();
-      Function<String, String> configProperties = injector.getInstance(ValueOfConfigurationKeyOrNull.class);
+      Function<String, String> configProperties = injector
+            .getInstance(ValueOfConfigurationKeyOrNull.class);
       IsoSpec isoSpec = IsoSpec
-               .builder()
-               .sourcePath(operatingSystemIso)
-               .installationScript(
-                        configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE).replace("HOSTNAME",
-                                 instanceVmSpec.getVmName())).build();
+            .builder()
+            .sourcePath(operatingSystemIso)
+            .installationScript(
+                  configProperties.apply(VIRTUALBOX_INSTALLATION_KEY_SEQUENCE)
+                        .replace("HOSTNAME", instanceVmSpec.getVmName()))
+            .build();
 
-      NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
-               .tcpRedirectRule("127.0.0.1", 2222, "", 22).build();
-      NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
-               .build();
-
-      NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
-      machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec).network(networkSpec).build();
+      NetworkAdapter networkAdapter = NetworkAdapter.builder()
+            .networkAttachmentType(NetworkAttachmentType.HostOnly).build();
+      NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard
+            .builder().addNetworkAdapter(networkAdapter)
+            .addHostInterfaceName("vboxnet0").slot(0L).build();
+      NetworkSpec networkSpec = NetworkSpec.builder()
+            .addNIC(networkInterfaceCard).build();
+      machineSpec = MasterSpec.builder().iso(isoSpec).vm(instanceVmSpec)
+            .network(networkSpec).build();
    }
 
    @Test
@@ -106,8 +110,8 @@
    @Test(dependsOnMethods="testEnsureMachineisLaunchedAndSessionIsUnlocked")
    public void testEnsureMachineCanBePoweredOffMoreThanOneTimeAndSessionIsUnlocked() {
       ISession cloneMachineSession = machineController.ensureMachineHasPowerDown(instanceName);
-      cloneMachineSession = machineController.ensureMachineHasPowerDown(instanceName);
-      assertTrue(cloneMachineSession.getState() == SessionState.Unlocked);
+      SessionState state = cloneMachineSession.getState();
+      assertTrue(state.equals(SessionState.Unlocked));
    }
 
    private IMachine cloneFromMaster() {
diff --git a/labs/virtualbox/src/test/resources/default-images.yaml b/labs/virtualbox/src/test/resources/default-images.yaml
index 4efa20d..fddcff3 100644
--- a/labs/virtualbox/src/test/resources/default-images.yaml
+++ b/labs/virtualbox/src/test/resources/default-images.yaml
@@ -15,7 +15,7 @@
                 fb=false debconf/frontend=noninteractive 
                 keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false 
                 initrd=/install/initrd.gz -- <Enter>
-      preseed_cfg: |                
+      preseed_cfg: |
                       ## Options to set on the command line
                       d-i debian-installer/locale string en_US.utf8
                       d-i console-setup/ask_detect boolean false
@@ -66,7 +66,7 @@
                       # debconf-get-selections --install
                       #Use mirror
                       choose-mirror-bin mirror/http/proxy string
-    - id: test-ubuntu-11.10-i386
+    - id: ubuntu-11.10-i386
       name: ubuntu-11.10-server-i386
       description: ubuntu 11.10 server (i386)
       os_arch: x86
@@ -132,4 +132,90 @@
                       d-i pkgsel/update-policy select none
                       # debconf-get-selections --install
                       #Use mirror
+                      choose-mirror-bin mirror/http/proxy string
+    - id: ubuntu-12.04.1-amd64
+      name: ubuntu-12.04.1-server-amd64
+      description: ubuntu 12.04.1 server (amd64)
+      os_arch: amd64
+      os_family: ubuntu
+      os_description: ubuntu
+      os_version: 12.04.1
+      os_64bit: true
+      iso: http://releases.ubuntu.com/12.04/ubuntu-12.04.1-server-amd64.iso
+      iso_md5: a8c667e871f48f3a662f3fbf1c3ddb17
+      keystroke_sequence: |
+                <Esc><Esc><Enter> 
+                /install/vmlinuz noapic preseed/url=http://10.0.2.2:8080/src/test/resources/preseed.cfg 
+                debian-installer=en_US auto locale=en_US kbd-chooser/method=us 
+                hostname=vmName 
+                fb=false debconf/frontend=noninteractive 
+                keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false 
+                initrd=/install/initrd.gz -- <Enter>
+      preseed_cfg: |
+                      ## Options to set on the command line
+                      d-i debian-installer/locale string en_US.utf8
+                      d-i console-setup/ask_detect boolean false
+                      d-i console-setup/layout string USA
+                      #d-i netcfg/get_hostname string dummy
+                      d-i netcfg/get_hostname string unassigned-hostname
+                      d-i netcfg/get_domain string unassigned-domain
+                      # Continue without a default route
+                      # Not working , specify a dummy in the DHCP
+                      #d-i netcfg/no_default_route boolean
+                      d-i time/zone string UTC
+                      d-i clock-setup/utc-auto boolean true
+                      d-i clock-setup/utc boolean true
+                      d-i kbd-chooser/method select American English
+                      d-i netcfg/wireless_wep string
+                      d-i base-installer/kernel/override-image string linux-server
+                      #d-i base-installer/kernel/override-image string linux-image-2.6.32-21-generic
+                      # Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive
+                      d-i debconf debconf/frontend select Noninteractive
+                      d-i pkgsel/install-language-support boolean false
+                      tasksel tasksel/first multiselect standard, ubuntu-server
+                      #d-i partman-auto/method string regular
+                      d-i partman-auto/method string lvm
+                      #d-i partman-auto/purge_lvm_from_device boolean true
+                      d-i partman-lvm/confirm boolean true
+                      d-i partman-lvm/device_remove_lvm boolean true
+                      d-i partman-auto/choose_recipe select atomic
+                      d-i partman/confirm_write_new_label boolean true
+                      d-i partman/confirm_nooverwrite boolean true
+                      d-i partman/choose_partition select finish
+                      d-i partman/confirm boolean true
+                      #http://ubuntu-virginia.ubuntuforums.org/showthread.php?p=9626883
+                      #Message: "write the changes to disk and configure lvm preseed"
+                      #http://serverfault.com/questions/189328/ubuntu-kickstart-installation-using-lvm-waits-for-input
+                      #preseed partman-lvm/confirm_nooverwrite boolean true
+                      # Write the changes to disks and configure LVM?
+                      d-i partman-lvm/confirm boolean true
+                      d-i partman-lvm/confirm_nooverwrite boolean true
+                      d-i partman-auto-lvm/guided_size string max
+                      ## Default user, we can get away with a recipe to change this
+                      d-i passwd/user-fullname string toor
+                      d-i passwd/username string toor
+                      d-i passwd/user-password password password
+                      d-i passwd/user-password-again password password
+                      d-i user-setup/encrypt-home boolean false
+                      d-i user-setup/allow-password-weak boolean true
+                      ## minimum is ssh and ntp
+                      # Individual additional packages to install
+                      d-i pkgsel/include string openssh-server ntp
+                      # Whether to upgrade packages after debootstrap.
+                      # Allowed values: none, safe-upgrade, full-upgrade
+                      d-i pkgsel/upgrade select full-upgrade
+                      d-i grub-installer/only_debian boolean true
+                      d-i grub-installer/with_other_os boolean true
+                      d-i finish-install/reboot_in_progress note
+                      #For the update
+                      d-i pkgsel/update-policy select none
+                      # debconf-get-selections --install
+                      #Use mirror
+                      #d-i apt-setup/use_mirror boolean true
+                      #d-i mirror/country string manual
+                      #choose-mirror-bin mirror/protocol string http
+                      #choose-mirror-bin mirror/http/hostname string 192.168.4.150
+                      #choose-mirror-bin mirror/http/directory string /ubuntu
+                      #choose-mirror-bin mirror/suite select maverick
+                      #d-i debian-installer/allow_unauthenticated string true
                       choose-mirror-bin mirror/http/proxy string
\ No newline at end of file
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2ProviderMetadata.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2ProviderMetadata.java
index 4cffbd3..ef304cb 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2ProviderMetadata.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/AWSEC2ProviderMetadata.java
@@ -69,7 +69,7 @@
       properties.setProperty(PROPERTY_EC2_AMI_QUERY,
                "owner-id=137112412989,801119661308,063491364108,099720109477,411009282317;state=available;image-type=machine");
       // amis that work with the cluster instances
-      properties.setProperty(PROPERTY_EC2_CC_REGIONS, Region.US_EAST_1 + "," + Region.EU_WEST_1);
+      properties.setProperty(PROPERTY_EC2_CC_REGIONS, Region.US_EAST_1 + "," + Region.US_WEST_2 + ","+ Region.EU_WEST_1);
       properties
                .setProperty(
                         PROPERTY_EC2_CC_AMI_QUERY,
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/AWSRunningInstance.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/AWSRunningInstance.java
index 9cb43cb..06605b2 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/AWSRunningInstance.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/AWSRunningInstance.java
@@ -31,7 +31,7 @@
 import org.jclouds.ec2.domain.RunningInstance;
 import org.jclouds.javax.annotation.Nullable;
 
-import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -241,13 +241,13 @@
       }
 
       @Override
-      public Builder groupId(String groupId) {
-         return Builder.class.cast(super.groupId(groupId));
+      public Builder groupName(String groupName) {
+         return Builder.class.cast(super.groupName(groupName));
       }
 
       @Override
-      public Builder groupIds(Iterable<String> groupIds) {
-         return Builder.class.cast(super.groupIds(groupIds));
+      public Builder groupNames(Iterable<String> groupNames) {
+         return Builder.class.cast(super.groupNames(groupNames));
       }
 
       @Override
@@ -364,74 +364,10 @@
    }
 
    @Override
-   public int hashCode() {
-      final int prime = 31;
-      int result = super.hashCode();
-      result = prime * result + ((placementGroup == null) ? 0 : placementGroup.hashCode());
-      result = prime * result + ((productCodes == null) ? 0 : productCodes.hashCode());
-      result = prime * result + ((spotInstanceRequestId == null) ? 0 : spotInstanceRequestId.hashCode());
-      result = prime * result + ((subnetId == null) ? 0 : subnetId.hashCode());
-      result = prime * result + ((vpcId == null) ? 0 : vpcId.hashCode());
-      result = prime * result + ((hypervisor == null) ? 0 : hypervisor.hashCode());
-      result = prime * result + ((tags == null) ? 0 : tags.hashCode());
-      return result;
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj)
-         return true;
-      if (!super.equals(obj))
-         return false;
-      if (getClass() != obj.getClass())
-         return false;
-      AWSRunningInstance other = (AWSRunningInstance) obj;
-      if (placementGroup == null) {
-         if (other.placementGroup != null)
-            return false;
-      } else if (!placementGroup.equals(other.placementGroup))
-         return false;
-      if (productCodes == null) {
-         if (other.productCodes != null)
-            return false;
-      } else if (!productCodes.equals(other.productCodes))
-         return false;
-      if (spotInstanceRequestId == null) {
-         if (other.spotInstanceRequestId != null)
-            return false;
-      } else if (!spotInstanceRequestId.equals(other.spotInstanceRequestId))
-         return false;
-      if (subnetId == null) {
-         if (other.subnetId != null)
-            return false;
-      } else if (!subnetId.equals(other.subnetId))
-         return false;
-      if (vpcId == null) {
-         if (other.vpcId != null)
-            return false;
-      } else if (!vpcId.equals(other.vpcId))
-         return false;
-      if (tags == null) {
-         if (other.tags != null)
-            return false;
-      } else if (!tags.equals(other.tags))
-         return false;
-      if (!Objects.equal(hypervisor, other.hypervisor))
-         return false;
-      return true;
-   }
-
-   @Override
-   public String toString() {
-      return "[region=" + region + ", availabilityZone=" + availabilityZone + ", instanceId=" + instanceId
-               + ", instanceState=" + rawState + ", instanceType=" + instanceType + ", virtualizationType="
-               + virtualizationType + ", imageId=" + imageId + ", ipAddress=" + ipAddress + ", dnsName=" + dnsName
-               + ", privateIpAddress=" + privateIpAddress + ", privateDnsName=" + privateDnsName + ", keyName="
-               + keyName + ", platform=" + platform + ", launchTime=" + launchTime + ", rootDeviceName="
-               + rootDeviceName + ", rootDeviceType=" + rootDeviceType + ", ebsBlockDevices=" + ebsBlockDevices
-               + ", monitoringState=" + monitoringState + ", placementGroup=" + placementGroup + ", productCodes="
-               + productCodes + ", spotInstanceRequestId=" + spotInstanceRequestId + ", subnetId=" + subnetId
-               + ", hypervisor=" + hypervisor + ", vpcId=" + vpcId + ", tags=" + tags + "]";
+   protected ToStringHelper string() {
+      return super.string().add("monitoringState", monitoringState).add("placementGroup", placementGroup)
+               .add("subnetId", subnetId).add("spotInstanceRequestId", spotInstanceRequestId).add("vpcId", vpcId)
+               .add("hypervisor", hypervisor).add("tags", tags);
    }
 
 }
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/PlacementGroup.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/PlacementGroup.java
index db0dfee..9250fc4 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/PlacementGroup.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/PlacementGroup.java
@@ -77,8 +77,12 @@
    }
 
    /**
-    * @return placement groups are in a region, however the namescope is global.
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
     */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Spot.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Spot.java
index c5b21c9..75e2d3c 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Spot.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/domain/Spot.java
@@ -92,6 +92,13 @@
       this.timestamp = checkNotNull(timestamp, "timestamp");
    }
 
+   /**
+    * To be removed in jclouds 1.6 <h4>Warning</h4>
+    * 
+    * Especially on EC2 clones that may not support regions, this value is fragile. Consider
+    * alternate means to determine context.
+    */
+   @Deprecated
    public String getRegion() {
       return region;
    }
diff --git a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/functions/SpotInstanceRequestToAWSRunningInstance.java b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/functions/SpotInstanceRequestToAWSRunningInstance.java
index 5c7fe7d..854000b 100644
--- a/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/functions/SpotInstanceRequestToAWSRunningInstance.java
+++ b/providers/aws-ec2/src/main/java/org/jclouds/aws/ec2/functions/SpotInstanceRequestToAWSRunningInstance.java
@@ -52,7 +52,7 @@
       builder.availabilityZone(spec.getAvailabilityZone());
       // TODO convert
       // builder.devices(spec.getBlockDeviceMappings());
-      builder.groupIds(spec.getSecurityGroupNames());
+      builder.groupNames(spec.getSecurityGroupNames());
       builder.imageId(spec.getImageId());
       builder.instanceType(spec.getInstanceType());
       builder.kernelId(spec.getKernelId());
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 6b1b383..5422ad9 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
@@ -38,10 +38,10 @@
 import org.jclouds.aws.ec2.services.AWSSecurityGroupClient;
 import org.jclouds.cloudwatch.CloudWatchApi;
 import org.jclouds.cloudwatch.CloudWatchAsyncApi;
-import org.jclouds.cloudwatch.domain.Datapoint;
 import org.jclouds.cloudwatch.domain.Dimension;
 import org.jclouds.cloudwatch.domain.EC2Constants;
 import org.jclouds.cloudwatch.domain.GetMetricStatistics;
+import org.jclouds.cloudwatch.domain.GetMetricStatisticsResponse;
 import org.jclouds.cloudwatch.domain.Statistics;
 import org.jclouds.cloudwatch.domain.Unit;
 import org.jclouds.compute.domain.ExecResponse;
@@ -170,7 +170,7 @@
                .modules(setupModules()).build();
 
          try {
-            Set<Datapoint> datapoints = monitoringContext.getApi().getMetricApiForRegion(instance.getRegion())
+            GetMetricStatisticsResponse datapoints = monitoringContext.getApi().getMetricApiForRegion(instance.getRegion())
                      .getMetricStatistics(GetMetricStatistics.builder()
                                                              .dimension(new Dimension(EC2Constants.Dimension.INSTANCE_ID, instance.getId()))
                                                              .unit(Unit.PERCENT)
@@ -187,7 +187,7 @@
          }
 
          // make sure we made our dummy group and also let in the user's group
-         assertEquals(newTreeSet(instance.getGroupIds()), ImmutableSortedSet.<String> of("jclouds#" + group, group));
+         assertEquals(newTreeSet(instance.getGroupNames()), ImmutableSortedSet.<String> of("jclouds#" + group, group));
 
          // make sure our dummy group has no rules
          SecurityGroup secgroup = getOnlyElement(securityGroupClient.describeSecurityGroupsInRegion(instance
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 00d3ba3..f6ac142 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
@@ -171,7 +171,7 @@
 
       Template defaultTemplate = view.getComputeService().templateBuilder().build();
       assert (defaultTemplate.getImage().getProviderId().startsWith("ami-")) : defaultTemplate;
-      assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "pv-2012.03.3");
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "pv-2012.09.rc-0");
       assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
       assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.AMZN_LINUX);
       assertEquals(defaultTemplate.getImage().getUserMetadata().get("rootDeviceType"), "ebs");
@@ -186,7 +186,7 @@
       Template defaultTemplate = view.getComputeService().templateBuilder().osFamily(OsFamily.AMZN_LINUX)
             .imageMatches(EC2ImagePredicates.rootDeviceType(RootDeviceType.INSTANCE_STORE)).build();
       assert (defaultTemplate.getImage().getProviderId().startsWith("ami-")) : defaultTemplate;
-      assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "pv-2012.03.3");
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "pv-2012.09.rc-0");
       assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
       assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.AMZN_LINUX);
       assertEquals(defaultTemplate.getImage().getUserMetadata().get("rootDeviceType"), "instance-store");
@@ -201,7 +201,7 @@
             .build();
       assert (fastestTemplate.getImage().getProviderId().startsWith("ami-")) : fastestTemplate;
       assertEquals(fastestTemplate.getHardware().getProviderId(), InstanceType.HI1_4XLARGE);
-      assertEquals(fastestTemplate.getImage().getOperatingSystem().getVersion(), "pv-2012.03.3");
+      assertEquals(fastestTemplate.getImage().getOperatingSystem().getVersion(), "pv-2012.09.rc-0");
       assertEquals(fastestTemplate.getImage().getOperatingSystem().is64Bit(), true);
       assertEquals(fastestTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.AMZN_LINUX);
       assertEquals(fastestTemplate.getImage().getUserMetadata().get("rootDeviceType"), "instance-store");
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/IncidentalResourcesGetCleanedUpLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/IncidentalResourcesGetCleanedUpLiveTest.java
index 9d52e60..3a2fc77 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/IncidentalResourcesGetCleanedUpLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/compute/IncidentalResourcesGetCleanedUpLiveTest.java
@@ -117,8 +117,8 @@
          assertNotNull(instance1.getKeyName());
          assertEquals(instance1.getRegion(), instance2.getRegion(), "Nodes are not in the same region");
          assertEquals(instance1.getKeyName(), instance2.getKeyName(), "Nodes do not have same key-pair name");
-         assertEquals(instance1.getGroupIds(), instance2.getGroupIds(), "Nodes are not in the same group");
-         assertEquals(instance1.getGroupIds(), ImmutableSet.of(expectedSecurityGroupName), "Nodes are not in the expected security group");
+         assertEquals(instance1.getGroupNames(), instance2.getGroupNames(), "Nodes are not in the same group");
+         assertEquals(instance1.getGroupNames(), ImmutableSet.of(expectedSecurityGroupName), "Nodes are not in the expected security group");
 
          // Assert a single key-pair and security group has been created
          String expectedKeyPairName = instance1.getKeyName();
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/SpotInstanceRequestToAWSRunningInstanceTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/SpotInstanceRequestToAWSRunningInstanceTest.java
index 4324994..76c1ce9 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/SpotInstanceRequestToAWSRunningInstanceTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/functions/SpotInstanceRequestToAWSRunningInstanceTest.java
@@ -66,7 +66,7 @@
             AWSRunningInstance.builder().region("us-east-1").instanceId("sir-228e6406")
                   .spotInstanceRequestId("sir-228e6406").instanceState(InstanceState.PENDING)
                   .rawState("open").imageId("ami-595a0a1c")
-                  .groupId("default").instanceType("m1.large")
+                  .groupName("default").instanceType("m1.large")
                   .tag("foo", "bar")
                   .tag("empty", "")
                   .hypervisor(Hypervisor.XEN)
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/parse/DescribeInstancesResponseTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/parse/DescribeInstancesResponseTest.java
new file mode 100644
index 0000000..646853f
--- /dev/null
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/parse/DescribeInstancesResponseTest.java
@@ -0,0 +1,114 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.aws.ec2.parse;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.util.Set;
+
+import org.jclouds.aws.ec2.domain.AWSRunningInstance;
+import org.jclouds.aws.ec2.domain.MonitoringState;
+import org.jclouds.aws.ec2.xml.AWSDescribeInstancesResponseHandler;
+import org.jclouds.date.DateService;
+import org.jclouds.ec2.domain.Attachment;
+import org.jclouds.ec2.domain.BlockDevice;
+import org.jclouds.ec2.domain.Hypervisor;
+import org.jclouds.ec2.domain.InstanceState;
+import org.jclouds.ec2.domain.Reservation;
+import org.jclouds.ec2.domain.RootDeviceType;
+import org.jclouds.ec2.domain.RunningInstance;
+import org.jclouds.ec2.xml.BaseEC2HandlerTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Tests behavior of {@code AWSDescribeInstancesResponseHandler}
+ * 
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "AWSDescribeInstancesResponseHandlerTest")
+public class DescribeInstancesResponseTest extends BaseEC2HandlerTest {
+
+   private DateService dateService;
+
+   @BeforeTest
+   @Override
+   protected void setUpInjector() {
+      super.setUpInjector();
+      dateService = injector.getInstance(DateService.class);
+      assert dateService != null;
+   }
+
+   public void test() {
+      InputStream is = getClass().getResourceAsStream("/describe_instances_pending.xml");
+
+      Set<Reservation<AWSRunningInstance>> expected = expected();
+
+      AWSDescribeInstancesResponseHandler handler = injector.getInstance(AWSDescribeInstancesResponseHandler.class);
+      Set<Reservation<? extends RunningInstance>> result = factory.create(handler).parse(is);
+
+      assertEquals(result.toString(), expected.toString());
+
+   }
+
+   public Set<Reservation<AWSRunningInstance>> expected() {
+      return ImmutableSet.of(Reservation.<AWSRunningInstance>builder()
+                         .region(defaultRegion)
+                         .reservationId("r-3f056a58")
+                         .ownerId("095072994936")
+//                                             <groupId>sg-f788299f</groupId>
+                         .groupName("launchpad_sec_group")
+//                                             <groupId>sg-7e512116</groupId>
+                         .groupName("jclouds#4c858090-f66c-4225-aa57-6fcaa42198ae")
+                         .instance(AWSRunningInstance.builder()
+                                  .region(defaultRegion)
+                                  .instanceId("i-32451248")
+                                  .imageId("ami-bf8131d6")
+                                  .rawState("pending")
+                                  .instanceState(InstanceState.PENDING)
+                                  .privateDnsName("ip-10-194-149-220.ec2.internal")
+                                  .dnsName("ec2-23-20-17-42.compute-1.amazonaws.com")
+                                  .keyName("jclouds#4c858090-f66c-4225-aa57-6fcaa42198ae#105")
+                                  .amiLaunchIndex("0")
+                                  .instanceType("c1.medium")
+                                  .launchTime(dateService.iso8601DateParse("2012-09-14T20:01:34.000Z"))
+                                  .availabilityZone("us-east-1d")
+//                                  .tenancy("default")
+                                  .kernelId("aki-825ea7eb")
+                                  .monitoringState(MonitoringState.DISABLED)
+                                  .privateIpAddress("10.194.149.220")
+                                  .ipAddress("23.20.17.42")
+                                  .securityGroupIdToName("sg-f788299f", "launchpad_sec_group")
+                                  .securityGroupIdToName("sg-7e512116", "jclouds#4c858090-f66c-4225-aa57-6fcaa42198ae")
+//                                  .architecture("x86_64")
+                                  .rootDeviceType(RootDeviceType.EBS)
+                                  .rootDeviceName("/dev/sda1")
+                                  .device("/dev/sda1", new BlockDevice("vol-b2beb3c9", Attachment.Status.ATTACHING, dateService.iso8601DateParse("2012-09-14T20:01:37.000Z"), true))
+                                  .virtualizationType("paravirtual")
+                                  .tag("Name", "4c858090-f66c-4225-aa57-6fcaa42198ae-32451248")
+                                  .hypervisor(Hypervisor.XEN)
+                                  .build()).build());
+   }
+   
+}
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/PlacementGroupClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/PlacementGroupClientLiveTest.java
index 9d33a3b..dc93bd9 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/PlacementGroupClientLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/PlacementGroupClientLiveTest.java
@@ -63,7 +63,7 @@
  */
 @Test(groups = "live", singleThreaded = true, testName = "PlacementGroupClientLiveTest")
 public class PlacementGroupClientLiveTest extends BaseComputeServiceContextLiveTest {
-   ArrayList<String> supportedRegions = newArrayList(Region.US_EAST_1, Region.EU_WEST_1);
+   ArrayList<String> supportedRegions = newArrayList(Region.US_EAST_1, Region.US_WEST_2, Region.EU_WEST_1);
 
    public PlacementGroupClientLiveTest() {
       provider = "aws-ec2";
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceClientLiveTest.java
index 7bbc22c..26188dc 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceClientLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/SpotInstanceClientLiveTest.java
@@ -41,7 +41,7 @@
 import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
 import org.jclouds.ec2.domain.InstanceType;
 import org.jclouds.predicates.RetryablePredicate;
-import org.testng.annotations.AfterTest;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -160,8 +160,9 @@
 
    public static final String PREFIX = System.getProperty("user.name") + "ec2";
 
-   @AfterTest
-   public void shutdown() {
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   protected void tearDownContext() {
       if (requests != null) {
          for (SpotInstanceRequest request : requests)
             client.getSpotInstanceServices().cancelSpotInstanceRequestsInRegion(request.getRegion(), request.getId());
@@ -170,5 +171,6 @@
       if (instance != null) {
          client.getInstanceServices().terminateInstancesInRegion(instance.getRegion(), instance.getId());
       }
+      super.tearDownContext();
    }
 }
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/TagClientLiveTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/TagClientLiveTest.java
index 42286e5..f6d3466 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/TagClientLiveTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/services/TagClientLiveTest.java
@@ -30,7 +30,7 @@
 import org.jclouds.aws.ec2.util.TagFilters;
 import org.jclouds.aws.ec2.util.TagFilters.ResourceType;
 import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
-import org.testng.annotations.AfterGroups;
+import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -69,9 +69,11 @@
       }
    }
 
-   @AfterGroups(groups = { "live" })
-   public void deleteSecurityGroup() {
+   @Override
+   @AfterClass(groups = { "integration", "live" })
+   protected void tearDownContext() {
        view.unwrap(AWSEC2ApiMetadata.CONTEXT_TOKEN).getApi().getSecurityGroupServices().deleteSecurityGroupInRegionById(null, testGroup);
+       super.tearDownContext();
    }
 
    public static final String PREFIX = System.getProperty("user.name") + "-ec2";
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSDescribeInstancesResponseHandlerTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSDescribeInstancesResponseHandlerTest.java
index 25aa26b..c247bf2 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSDescribeInstancesResponseHandlerTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSDescribeInstancesResponseHandlerTest.java
@@ -31,7 +31,6 @@
 import org.jclouds.ec2.domain.BlockDevice;
 import org.jclouds.ec2.domain.Hypervisor;
 import org.jclouds.ec2.domain.InstanceState;
-import org.jclouds.ec2.domain.InstanceType;
 import org.jclouds.ec2.domain.Reservation;
 import org.jclouds.ec2.domain.RootDeviceType;
 import org.jclouds.ec2.domain.RunningInstance;
@@ -71,44 +70,13 @@
       assert dateService != null;
    }
 
-   public void testWhenRunning() throws UnknownHostException {
-
-      Set<Reservation<AWSRunningInstance>> contents = ImmutableSet.of(
-              new Reservation<AWSRunningInstance>(defaultRegion, ImmutableSet.of("adriancole.ec2ingress"), ImmutableSet.of(
-                      new AWSRunningInstance.Builder()
-                          .region(defaultRegion)
-                          .groupId("adriancole.ec2ingress")
-                          .amiLaunchIndex("0")
-                          .dnsName("ec2-174-129-81-68.compute-1.amazonaws.com")
-                          .imageId("ami-82e4b5c7")
-                          .instanceId("i-0799056f")
-                          .instanceState(InstanceState.RUNNING)
-                          .rawState("running")
-                          .instanceType(InstanceType.M1_SMALL)
-                          .ipAddress("174.129.81.68")
-                          .kernelId("aki-a71cf9ce")
-                          .keyName("adriancole.ec21")
-                          .launchTime(dateService.iso8601DateParse("2009-11-09T03:00:34.000Z"))
-                          .monitoringState(MonitoringState.DISABLED)
-                          .availabilityZone("us-east-1c")
-                          .virtualizationType("paravirtual")
-                          .privateDnsName("ip-10-243-42-70.ec2.internal")
-                          .privateIpAddress("10.243.42.70")
-                          .ramdiskId("ari-a51cf9cc")
-                          .rootDeviceType(RootDeviceType.INSTANCE_STORE)
-                          .hypervisor(Hypervisor.XEN)
-                          .build()),
-                  "993194456877", null, "r-a3c508cb"));
-
-      Set<Reservation<? extends RunningInstance>> result = parseAWSRunningInstances("/describe_instances_running.xml");
-
-      assertEquals(result.toString(), contents.toString());
-   }
 
    public void testWhenRunningLatest() throws UnknownHostException {
-      Set<Reservation<AWSRunningInstance>> contents = ImmutableSet.of(new Reservation<AWSRunningInstance>(
-            defaultRegion, ImmutableSet.of("jclouds#ec2-s#us-east-1"), ImmutableSet.of(
-                  new AWSRunningInstance.Builder()
+      Set<Reservation<AWSRunningInstance>> contents = ImmutableSet.of(Reservation.<AWSRunningInstance>builder()
+               .region(defaultRegion)
+               .reservationId("r-0f4c2160")
+               .groupName("jclouds#zkclustertest#us-east-1")
+               .instance(AWSRunningInstance.builder()
                         .region(defaultRegion)
                         .instanceId("i-911444f0")
                         .imageId("ami-63be790a")
@@ -135,8 +103,8 @@
                               new BlockDevice("vol-5829fc32", Attachment.Status.ATTACHED, dateService
                                     .iso8601DateParse("2011-08-16T13:41:19.000Z"), true))
                         .hypervisor(Hypervisor.XEN)
-                        .virtualizationType("paravirtual").build(),//
-                  new AWSRunningInstance.Builder()
+                        .virtualizationType("paravirtual").build())
+               .instance(AWSRunningInstance.builder()
                         .region(defaultRegion)
                         .instanceId("i-931444f2")
                         .imageId("ami-63be790a")
@@ -162,7 +130,7 @@
                               new BlockDevice("vol-5029fc3a", Attachment.Status.ATTACHED, dateService
                                     .iso8601DateParse("2011-08-16T13:41:19.000Z"), true))
                         .hypervisor(Hypervisor.XEN)
-                        .virtualizationType("paravirtual").build()), defaultRegion, defaultRegion, defaultRegion));
+                        .virtualizationType("paravirtual").build()).build());
 
       Set<Reservation<? extends RunningInstance>> result = parseAWSRunningInstances("/describe_instances_latest.xml");
 
@@ -175,76 +143,6 @@
       parseAWSRunningInstances("/describe_instances_3.xml");
    }
 
-   public void testApplyInputStream() {
-      Set<Reservation<AWSRunningInstance>> contents = ImmutableSet.of(new Reservation<AWSRunningInstance>(
-            defaultRegion, ImmutableSet.of("default"), ImmutableSet.of(
-                  new AWSRunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("23")
-                        .dnsName("ec2-72-44-33-4.compute-1.amazonaws.com").imageId("ami-6ea54007")
-                        .instanceId("i-28a64341").instanceState(InstanceState.RUNNING).rawState("running")
-                        .instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName("example-key-name")
-                        .launchTime(dateService.iso8601DateParse("2007-08-07T11:54:42.000Z"))
-                        .monitoringState(MonitoringState.DISABLED).availabilityZone("us-east-1b")
-                        .virtualizationType("paravirtual").privateDnsName("10-251-50-132.ec2.internal")
-                        .productCode("774F4FF8").ramdiskId("ari-badbad00")
-                        .hypervisor(Hypervisor.XEN)
-                        .rootDeviceType(RootDeviceType.INSTANCE_STORE).build(),
-                  new AWSRunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("23")
-                        .dnsName("ec2-72-44-33-6.compute-1.amazonaws.com").imageId("ami-6ea54007")
-                        .instanceId("i-28a64435").instanceState(InstanceState.RUNNING).rawState("running")
-                        .instanceType(InstanceType.M1_LARGE).kernelId("aki-ba3adfd3").keyName("example-key-name")
-                        .launchTime(dateService.iso8601DateParse("2007-08-07T11:54:42.000Z"))
-                        .monitoringState(MonitoringState.DISABLED).availabilityZone("us-east-1b")
-                        .virtualizationType("paravirtual").privateDnsName("10-251-50-134.ec2.internal")
-                        .productCode("774F4FF8").ramdiskId("ari-badbad00")
-                        .hypervisor(Hypervisor.XEN)
-                        .rootDeviceType(RootDeviceType.INSTANCE_STORE).build()), "UYY3TLBUXIEON5NQVUUX6OMPWBZIQNFM",
-            null, "r-44a5402d"));
-
-      Set<Reservation<? extends RunningInstance>> result = parseAWSRunningInstances("/describe_instances.xml");
-
-      assertEquals(result.toString(), contents.toString());
-   }
-
-   public void testEBS() throws UnknownHostException {
-
-      Set<Reservation<AWSRunningInstance>> contents = ImmutableSet.of(new Reservation<AWSRunningInstance>(
-            defaultRegion, ImmutableSet.of("adriancole.ec2ebsingress"), ImmutableSet
-                  .of(new AWSRunningInstance.Builder()
-                        .region(defaultRegion)
-                        .groupId("adriancole.ec2ebsingress")
-                        .amiLaunchIndex("0")
-                        .dnsName("ec2-75-101-203-146.compute-1.amazonaws.com")
-                        .imageId("ami-849875ed")
-                        .instanceId("i-e564438d")
-                        .instanceState(InstanceState.RUNNING)
-                        .rawState("running")
-                        .instanceType(InstanceType.M1_SMALL)
-                        .ipAddress("75.101.203.146")
-                        .kernelId("aki-a71cf9ce")
-                        .keyName("adriancole.ec2ebs1")
-                        .launchTime(dateService.iso8601DateParse("2009-12-30T04:06:23.000Z"))
-                        .monitoringState(MonitoringState.DISABLED)
-                        .availabilityZone("us-east-1b")
-                        .placementGroup("placement")
-                        .virtualizationType("hvm")
-                        .privateDnsName("domU-12-31-39-09-CE-53.compute-1.internal")
-                        .privateIpAddress("10.210.209.157")
-                        .ramdiskId("ari-a51cf9cc")
-                        .hypervisor(Hypervisor.XEN)
-                        .rootDeviceType(RootDeviceType.EBS)
-                        .rootDeviceName("/dev/sda1")
-                        .hypervisor(Hypervisor.XEN)
-                        .device(
-                              "/dev/sda1",
-                              new BlockDevice("vol-dc6ca8b5", Attachment.Status.ATTACHED, dateService
-                                    .iso8601DateParse("2009-12-30T04:06:29.000Z"), true)).build()), "993194456877",
-            null, "r-596dd731"));
-
-      Set<Reservation<? extends RunningInstance>> result = parseAWSRunningInstances("/describe_instances_ebs.xml");
-
-      assertEquals(result.toString(), contents.toString());
-   }
-
    static ParseSax<Set<Reservation<? extends RunningInstance>>> createParser() {
       Injector injector = Guice.createInjector(new SaxParserModule(), new AbstractModule() {
 
diff --git a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSRunInstancesResponseHandlerTest.java b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSRunInstancesResponseHandlerTest.java
index 09547f9..73d4a37 100644
--- a/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSRunInstancesResponseHandlerTest.java
+++ b/providers/aws-ec2/src/test/java/org/jclouds/aws/ec2/xml/AWSRunInstancesResponseHandlerTest.java
@@ -44,7 +44,6 @@
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.TypeLiteral;
@@ -82,28 +81,25 @@
 
       InputStream is = getClass().getResourceAsStream("/run_instances.xml");
 
-      Reservation<? extends AWSRunningInstance> expected = new Reservation<AWSRunningInstance>(defaultRegion,
-            ImmutableSet.of("default"), ImmutableSet.of(
-
-               new AWSRunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("0").imageId(
+      Reservation<? extends AWSRunningInstance> expected = Reservation.<AWSRunningInstance>builder()
+               .region(defaultRegion)
+               .instance(AWSRunningInstance.builder().region(defaultRegion).groupName("default").amiLaunchIndex("0").imageId(
                         "ami-60a54009").instanceId("i-2ba64342").instanceState(InstanceState.PENDING).rawState(
                         "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
                         dateService.iso8601DateParse("2007-08-07T11:51:50.000Z")).hypervisor(Hypervisor.XEN)
-                        .monitoringState(MonitoringState.ENABLED).availabilityZone("us-east-1b").build(),
-
-               new AWSRunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("1").imageId(
+                        .monitoringState(MonitoringState.ENABLED).availabilityZone("us-east-1b").build())
+               .instance(AWSRunningInstance.builder().region(defaultRegion).groupName("default").amiLaunchIndex("1").imageId(
                         "ami-60a54009").instanceId("i-2bc64242").instanceState(InstanceState.PENDING).rawState(
                         "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
                         dateService.iso8601DateParse("2007-08-07T11:51:50.000Z")).hypervisor(Hypervisor.XEN)
-                        .monitoringState(MonitoringState.ENABLED).availabilityZone("us-east-1b").build(),
-
-               new AWSRunningInstance.Builder().region(defaultRegion).groupId("default").amiLaunchIndex("2").imageId(
+                        .monitoringState(MonitoringState.ENABLED).availabilityZone("us-east-1b").build())
+               .instance(AWSRunningInstance.builder().region(defaultRegion).groupName("default").amiLaunchIndex("2").imageId(
                         "ami-60a54009").instanceId("i-2be64332").instanceState(InstanceState.PENDING).rawState(
                         "pending").instanceType(InstanceType.M1_SMALL).keyName("example-key-name").launchTime(
                         dateService.iso8601DateParse("2007-08-07T11:51:50.000Z")).hypervisor(Hypervisor.XEN)
                         .monitoringState(MonitoringState.ENABLED).availabilityZone("us-east-1b").build())
-
-            , "AIDADH4IGTRXXKCD", null, "r-47a5402e");
+               .ownerId("AIDADH4IGTRXXKCD")
+               .reservationId("r-47a5402e").build();
 
       AWSRunInstancesResponseHandler handler = injector.getInstance(AWSRunInstancesResponseHandler.class);
       addDefaultRegionToHandler(handler);
diff --git a/providers/aws-ec2/src/test/resources/describe_instances_pending.xml b/providers/aws-ec2/src/test/resources/describe_instances_pending.xml
new file mode 100644
index 0000000..92f9f4e
--- /dev/null
+++ b/providers/aws-ec2/src/test/resources/describe_instances_pending.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
+    <requestId>dcd37ecf-e5b6-462b-99a8-112427b3e3a2</requestId>
+    <reservationSet>
+        <item>
+            <reservationId>r-3f056a58</reservationId>
+            <ownerId>095072994936</ownerId>
+            <groupSet>
+                <item>
+                    <groupId>sg-f788299f</groupId>
+                    <groupName>launchpad_sec_group</groupName>
+                </item>
+                <item>
+                    <groupId>sg-7e512116</groupId>
+                    <groupName>jclouds#4c858090-f66c-4225-aa57-6fcaa42198ae</groupName>
+                </item>
+            </groupSet>
+            <instancesSet>
+                <item>
+                    <instanceId>i-32451248</instanceId>
+                    <imageId>ami-bf8131d6</imageId>
+                    <instanceState>
+                        <code>0</code>
+                        <name>pending</name>
+                    </instanceState>
+                    <privateDnsName>ip-10-194-149-220.ec2.internal</privateDnsName>
+                    <dnsName>ec2-23-20-17-42.compute-1.amazonaws.com</dnsName>
+                    <reason/>
+                    <keyName>jclouds#4c858090-f66c-4225-aa57-6fcaa42198ae#105</keyName>
+                    <amiLaunchIndex>0</amiLaunchIndex>
+                    <productCodes/>
+                    <instanceType>c1.medium</instanceType>
+                    <launchTime>2012-09-14T20:01:34.000Z</launchTime>
+                    <placement>
+                        <availabilityZone>us-east-1d</availabilityZone>
+                        <groupName/>
+                        <tenancy>default</tenancy>
+                    </placement>
+                    <kernelId>aki-825ea7eb</kernelId>
+                    <monitoring>
+                        <state>disabled</state>
+                    </monitoring>
+                    <privateIpAddress>10.194.149.220</privateIpAddress>
+                    <ipAddress>23.20.17.42</ipAddress>
+                    <groupSet>
+                        <item>
+                            <groupId>sg-f788299f</groupId>
+                            <groupName>launchpad_sec_group</groupName>
+                        </item>
+                        <item>
+                            <groupId>sg-7e512116</groupId>
+                            <groupName>jclouds#4c858090-f66c-4225-aa57-6fcaa42198ae</groupName>
+                        </item>
+                    </groupSet>
+                    <architecture>x86_64</architecture>
+                    <rootDeviceType>ebs</rootDeviceType>
+                    <rootDeviceName>/dev/sda1</rootDeviceName>
+                    <blockDeviceMapping>
+                        <item>
+                            <deviceName>/dev/sda1</deviceName>
+                            <ebs>
+                                <volumeId>vol-b2beb3c9</volumeId>
+                                <status>attaching</status>
+                                <attachTime>2012-09-14T20:01:37.000Z</attachTime>
+                                <deleteOnTermination>true</deleteOnTermination>
+                            </ebs>
+                        </item>
+                    </blockDeviceMapping>
+                    <virtualizationType>paravirtual</virtualizationType>
+                    <clientToken/>
+                    <tagSet>
+                        <item>
+                            <key>Name</key>
+                            <value>4c858090-f66c-4225-aa57-6fcaa42198ae-32451248</value>
+                        </item>
+                    </tagSet>
+                    <hypervisor>xen</hypervisor>
+                </item>
+            </instancesSet>
+        </item>
+    </reservationSet>
+</DescribeInstancesResponse>
\ No newline at end of file
diff --git a/providers/aws-sqs/pom.xml b/providers/aws-sqs/pom.xml
new file mode 100644
index 0000000..233f329
--- /dev/null
+++ b/providers/aws-sqs/pom.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to jclouds, Inc. (jclouds) under one or more
+    contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  jclouds licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-queue" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.jclouds</groupId>
+        <artifactId>jclouds-project</artifactId>
+        <version>1.5.0-SNAPSHOT</version>
+        <relativePath>../../project/pom.xml</relativePath>
+    </parent>
+    <groupId>org.jclouds.provider</groupId>
+    <artifactId>aws-sqs</artifactId>
+    <name>jclouds Amazon Simple Queue Service provider</name>
+    <description>Simple Queue Service implementation targeted to Amazon Web Services</description>
+    <packaging>bundle</packaging>
+
+    <properties>
+        <test.aws-sqs.endpoint>https://sqs.us-east-1.amazonaws.com</test.aws-sqs.endpoint>
+        <test.aws-sqs.api-version>2011-10-01</test.aws-sqs.api-version>
+        <test.aws-sqs.build-version></test.aws-sqs.build-version>
+        <test.aws-sqs.identity>${test.aws.identity}</test.aws-sqs.identity>
+        <test.aws-sqs.credential>${test.aws.credential}</test.aws-sqs.credential>
+
+      <jclouds.osgi.export>org.jclouds.aws.sqs*;version="${project.version}"</jclouds.osgi.export>
+      <jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jclouds.api</groupId>
+            <artifactId>sqs</artifactId>
+            <version>${project.version}</version>
+            <type>jar</type>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds.api</groupId>
+            <artifactId>sqs</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jclouds.driver</groupId>
+            <artifactId>jclouds-slf4j</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <version>1.0.0</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>live</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <systemPropertyVariables>
+                                        <test.aws-sqs.endpoint>${test.aws-sqs.endpoint}</test.aws-sqs.endpoint>
+                                        <test.aws-sqs.api-version>${test.aws-sqs.api-version}</test.aws-sqs.api-version>
+                                        <test.aws-sqs.build-version>${test.aws-sqs.build-version}</test.aws-sqs.build-version>
+                                        <test.aws-sqs.identity>${test.aws-sqs.identity}</test.aws-sqs.identity>
+                                        <test.aws-sqs.credential>${test.aws-sqs.credential}</test.aws-sqs.credential>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/providers/aws-sqs/src/main/java/org/jclouds/aws/sqs/AWSSQSProviderMetadata.java b/providers/aws-sqs/src/main/java/org/jclouds/aws/sqs/AWSSQSProviderMetadata.java
new file mode 100644
index 0000000..5b85c98
--- /dev/null
+++ b/providers/aws-sqs/src/main/java/org/jclouds/aws/sqs/AWSSQSProviderMetadata.java
@@ -0,0 +1,107 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.aws.sqs;
+
+import static org.jclouds.aws.domain.Region.AP_NORTHEAST_1;
+import static org.jclouds.aws.domain.Region.AP_SOUTHEAST_1;
+import static org.jclouds.aws.domain.Region.EU_WEST_1;
+import static org.jclouds.aws.domain.Region.SA_EAST_1;
+import static org.jclouds.aws.domain.Region.US_EAST_1;
+import static org.jclouds.aws.domain.Region.US_WEST_1;
+import static org.jclouds.aws.domain.Region.US_WEST_2;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.aws.domain.Region;
+import org.jclouds.sqs.SQSApiMetadata;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+
+/**
+ * Implementation of @ link org.jclouds.types.ProviderMetadata} for Amazon's Simple Queue Service
+ * provider.
+ * 
+ * @author Adrian Cole
+ */
+public class AWSSQSProviderMetadata extends BaseProviderMetadata {
+   
+   /** The serialVersionUID */
+   private static final long serialVersionUID = 7750012233546655021L;
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   @Override
+   public Builder toBuilder() {
+      return Builder.class.cast(builder().fromProviderMetadata(this));
+   }
+   
+   public AWSSQSProviderMetadata() {
+      super(builder());
+   }
+
+   public AWSSQSProviderMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = new Properties();
+      properties.putAll(Region.regionProperties());
+      properties.setProperty(PROPERTY_REGION + "." + US_EAST_1 + ".endpoint",
+            "https://sqs.us-east-1.amazonaws.com");
+      properties.setProperty(PROPERTY_REGION + "." + US_WEST_1 + ".endpoint",
+            "https://sqs.us-west-1.amazonaws.com");
+      properties.setProperty(PROPERTY_REGION + "." + US_WEST_2 + ".endpoint",
+            "https://sqs.us-west-2.amazonaws.com");
+      properties.setProperty(PROPERTY_REGION + "." + SA_EAST_1 + ".endpoint",
+            "https://sqs.sa-east-1.amazonaws.com");      
+      properties.setProperty(PROPERTY_REGION + "." + EU_WEST_1 + ".endpoint",
+            "https://sqs.eu-west-1.amazonaws.com");
+      properties.setProperty(PROPERTY_REGION + "." + AP_SOUTHEAST_1 + ".endpoint",
+            "https://sqs.ap-southeast-1.amazonaws.com");
+      properties.setProperty(PROPERTY_REGION + "." + AP_NORTHEAST_1 + ".endpoint",
+            "https://sqs.ap-northeast-1.amazonaws.com");
+      return properties;
+   }
+   
+   public static class Builder extends BaseProviderMetadata.Builder {
+
+      protected Builder(){
+         id("aws-sqs")
+         .name("Amazon Simple Queue Service")
+         .endpoint("https://sqs.us-east-1.amazonaws.com")
+         .homepage(URI.create("http://aws.amazon.com/sqs"))
+         .console(URI.create("https://console.aws.amazon.com/ec2/home"))
+         .linkedServices("aws-ec2", "aws-rds", "aws-sqs", "aws-elb", "aws-iam","aws-cloudwatch", "aws-s3", "aws-simpledb")
+         .iso3166Codes("US-VA", "US-CA", "BR-SP", "US-OR", "IE", "SG", "JP-13")
+         .apiMetadata(new SQSApiMetadata())
+         .defaultProperties(AWSSQSProviderMetadata.defaultProperties());
+      }
+
+      @Override
+      public Builder fromProviderMetadata(
+            ProviderMetadata in) {
+         super.fromProviderMetadata(in);
+         return this;
+      }
+   }
+}
diff --git a/providers/aws-sqs/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/providers/aws-sqs/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
new file mode 100644
index 0000000..6f797d6
--- /dev/null
+++ b/providers/aws-sqs/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
@@ -0,0 +1 @@
+org.jclouds.aws.sqs.AWSSQSProviderMetadata
diff --git a/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/AWSSQSProviderTest.java b/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/AWSSQSProviderTest.java
new file mode 100644
index 0000000..8b137f7
--- /dev/null
+++ b/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/AWSSQSProviderTest.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.aws.sqs;
+
+import org.jclouds.sqs.SQSApiMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadataTest;
+import org.testng.annotations.Test;
+
+/**
+ * The AWSSQSProviderTest tests the org.jclouds.providers.AWSSQSProvider class.
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "AWSSQSProviderTest")
+public class AWSSQSProviderTest extends BaseProviderMetadataTest {
+
+   public AWSSQSProviderTest() {
+      super(new AWSSQSProviderMetadata(), new SQSApiMetadata());
+   }
+}
diff --git a/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSMessageApiLiveTest.java b/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSMessageApiLiveTest.java
new file mode 100644
index 0000000..43d1c95
--- /dev/null
+++ b/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSMessageApiLiveTest.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.aws.sqs.features;
+
+import org.jclouds.sqs.features.MessageApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "AWSMessageApiLiveTest")
+public class AWSMessageApiLiveTest extends MessageApiLiveTest {
+
+   public AWSMessageApiLiveTest() {
+      provider = "aws-sqs";
+   }
+
+}
diff --git a/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSPermissionApiLiveTest.java b/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSPermissionApiLiveTest.java
new file mode 100644
index 0000000..14fa423
--- /dev/null
+++ b/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSPermissionApiLiveTest.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.aws.sqs.features;
+
+import org.jclouds.sqs.features.PermissionApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "AWSPermissionApiLiveTest")
+public class AWSPermissionApiLiveTest extends PermissionApiLiveTest {
+
+   public AWSPermissionApiLiveTest() {
+      provider = "aws-sqs";
+   }
+
+}
diff --git a/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSQueueApiLiveTest.java b/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSQueueApiLiveTest.java
new file mode 100644
index 0000000..0065477
--- /dev/null
+++ b/providers/aws-sqs/src/test/java/org/jclouds/aws/sqs/features/AWSQueueApiLiveTest.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.aws.sqs.features;
+
+import org.jclouds.sqs.features.QueueApiLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "AWSQueueApiLiveTest")
+public class AWSQueueApiLiveTest extends QueueApiLiveTest {
+
+   public AWSQueueApiLiveTest() {
+      provider = "aws-sqs";
+   }
+
+}
diff --git a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobRequestSigner.java b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobRequestSigner.java
index 535d720..72e881a 100644
--- a/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobRequestSigner.java
+++ b/providers/azureblob/src/main/java/org/jclouds/azureblob/blobstore/AzureBlobRequestSigner.java
@@ -67,11 +67,21 @@
    }
 
    @Override
+   public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signPutBlob(String container, Blob blob) {
       return cleanRequest(processor.createRequest(createMethod, container, blobToBlob.apply(blob)));
    }
 
    @Override
+   public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signRemoveBlob(String container, String name) {
       return cleanRequest(processor.createRequest(deleteMethod, container, name));
    }
diff --git a/providers/cloudfiles-us/pom.xml b/providers/cloudfiles-us/pom.xml
index 26d9b32..8acaa45 100644
--- a/providers/cloudfiles-us/pom.xml
+++ b/providers/cloudfiles-us/pom.xml
@@ -35,6 +35,7 @@
 
     <properties>
         <test.initializer>org.jclouds.rackspace.cloudfiles.blobstore.integration.CloudFilesUSTestInitializer</test.initializer>
+        <test.blobstore.container-count>15</test.blobstore.container-count>
         <test.cloudfiles-us.endpoint>https://auth.api.rackspacecloud.com</test.cloudfiles-us.endpoint>
         <test.cloudfiles-us.api-version>1.0</test.cloudfiles-us.api-version>
         <test.cloudfiles-us.build-version />
@@ -112,6 +113,7 @@
                                 <configuration>
                                     <threadCount>1</threadCount>
                                     <systemPropertyVariables>
+                                        <test.blobstore.container-count>${test.blobstore.container-count}</test.blobstore.container-count>
                                         <test.cloudfiles-us.endpoint>${test.cloudfiles-us.endpoint}</test.cloudfiles-us.endpoint>
                                         <test.cloudfiles-us.api-version>${test.cloudfiles-us.api-version}</test.cloudfiles-us.api-version>
                                         <test.cloudfiles-us.build-version>${test.cloudfiles-us.build-version}</test.cloudfiles-us.build-version>
diff --git a/providers/cloudsigma-lvs/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaLasVegasTemplateBuilderLiveTest.java b/providers/cloudsigma-lvs/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaLasVegasTemplateBuilderLiveTest.java
index 4c6c3c2..20881a0 100644
--- a/providers/cloudsigma-lvs/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaLasVegasTemplateBuilderLiveTest.java
+++ b/providers/cloudsigma-lvs/src/test/java/org/jclouds/cloudsigma/compute/CloudSigmaLasVegasTemplateBuilderLiveTest.java
@@ -51,23 +51,22 @@
          @Override
          public boolean apply(OsFamilyVersion64Bit input) {
             switch (input.family) {
-            case UBUNTU:
-               return (input.version.equals("11.04") && input.is64Bit)
-                     || (input.version.equals("11.10") && !input.is64Bit) || input.version.equals("")
-                     || input.version.equals("10.04");
-            case SOLARIS:
-               return input.version.equals("") && input.is64Bit;
-            case DEBIAN:
-               return false;
-            case CENTOS:
-               return (input.version.equals("") || input.version.equals("5.7") || input.version.equals("6.0"))
-                     && input.is64Bit;
-            case WINDOWS:
-               return (input.version.equals("2008 R2") || (input.version.equals("2003") || input.version.equals(""))
-                     && input.is64Bit)
-                     || (input.version.equals("") && !input.is64Bit);
-            default:
-               return false;
+               case UBUNTU:
+                  return (ImmutableSet.of("11.04", "10.10").contains(input.version) && input.is64Bit)
+                           || (input.version.equals("11.10") && !input.is64Bit) || input.version.equals("")
+                           || input.version.equals("10.04") || input.version.equals("12.04");
+               case SOLARIS:
+                  return (input.version.equals("") || input.version.equals("10")) && input.is64Bit;
+               case DEBIAN:
+                  return input.version.equals("") || (input.version.equals("5.0") && !input.is64Bit)
+                           || (input.version.equals("6.0") && input.is64Bit);
+               case CENTOS:
+                  return (input.version.equals("") || input.version.equals("5.5") || input.version.equals("5.7") || input.version
+                           .equals("6.0")) && input.is64Bit;
+               case WINDOWS:
+                  return input.version.equals("2008") || input.version.equals("2003") || input.version.equals("");
+               default:
+                  return false;
             }
          }
 
diff --git a/providers/glesys/pom.xml b/providers/glesys/pom.xml
new file mode 100644
index 0000000..c420d3e
--- /dev/null
+++ b/providers/glesys/pom.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  Licensed to jclouds, Inc. (jclouds) under one or more
+  contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  jclouds licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.jclouds</groupId>
+    <artifactId>jclouds-project</artifactId>
+    <version>1.5.0-SNAPSHOT</version>
+    <relativePath>../../project/pom.xml</relativePath>
+  </parent>
+  <groupId>org.jclouds.provider</groupId>
+  <artifactId>glesys</artifactId>
+  <name>jclouds GleSYS core</name>
+  <description>jclouds components to access GleSYS</description>
+  <packaging>bundle</packaging>
+
+  <properties>
+    <test.glesys.endpoint>https://api.glesys.com</test.glesys.endpoint>
+    <test.glesys.api-version>1</test.glesys.api-version>
+    <test.glesys.build-version>3.5.0</test.glesys.build-version>
+    <test.glesys.identity>FIXME</test.glesys.identity>
+    <test.glesys.credential>FIXME</test.glesys.credential>
+    <test.glesys.template>osFamily=UBUNTU,osVersionMatches=1[012].[01][04],os64Bit=true,minRam=768</test.glesys.template>
+    <jclouds.osgi.export>org.jclouds.glesys*;version="${project.version}"</jclouds.osgi.export>
+    <jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.jclouds</groupId>
+      <artifactId>jclouds-compute</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jclouds</groupId>
+      <artifactId>jclouds-core</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jclouds</groupId>
+      <artifactId>jclouds-compute</artifactId>
+      <version>${project.version}</version>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jclouds.driver</groupId>
+      <artifactId>jclouds-log4j</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.jclouds.driver</groupId>
+      <artifactId>jclouds-sshj</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <profiles>
+    <profile>
+      <id>live</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>integration</id>
+                <phase>integration-test</phase>
+                <goals>
+                  <goal>test</goal>
+                </goals>
+                <configuration>
+                  <systemPropertyVariables>
+                    <test.glesys.endpoint>${test.glesys.endpoint}</test.glesys.endpoint>
+                    <test.glesys.api-version>${test.glesys.api-version}</test.glesys.api-version>
+                    <test.glesys.build-version>${test.glesys.build-version}</test.glesys.build-version>
+                    <test.glesys.identity>${test.glesys.identity}</test.glesys.identity>
+                    <test.glesys.credential>${test.glesys.credential}</test.glesys.credential>
+                    <test.glesys.template>${test.glesys.template}</test.glesys.template>
+                  </systemPropertyVariables>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSApi.java
new file mode 100644
index 0000000..cdc7f49
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSApi.java
@@ -0,0 +1,72 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.glesys.features.ArchiveApi;
+import org.jclouds.glesys.features.DomainApi;
+import org.jclouds.glesys.features.EmailAccountApi;
+import org.jclouds.glesys.features.IpApi;
+import org.jclouds.glesys.features.ServerApi;
+import org.jclouds.rest.annotations.Delegate;
+
+/**
+ * Provides synchronous access to GleSYS.
+ * <p/>
+ * 
+ * @see GleSYSAsyncApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ * @author Adrian Cole
+ */
+@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+public interface GleSYSApi {
+
+   /**
+    * Provides synchronous access to Server features.
+    */
+   @Delegate
+   ServerApi getServerApi();
+
+   /**
+    * Provides synchronous access to Ip Address features.
+    */
+   @Delegate
+   IpApi getIpApi();
+
+   /**
+    * Provides synchronous access to Archive features.
+    */
+   @Delegate
+   ArchiveApi getArchiveApi();
+
+   /**
+    * Provides synchronous access to DNS features.
+    */
+   @Delegate
+   DomainApi getDomainApi();
+
+   /**
+    * Provides synchronous access to E-Mail features.
+    */
+   @Delegate
+   EmailAccountApi getEmailAccountApi();
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSApiMetadata.java b/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSApiMetadata.java
new file mode 100644
index 0000000..357d6bc
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSApiMetadata.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.glesys.compute.config.GleSYSComputeServiceContextModule;
+import org.jclouds.glesys.config.GleSYSRestClientModule;
+import org.jclouds.rest.RestContext;
+import org.jclouds.rest.internal.BaseRestApiMetadata;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for  API
+ * 
+ * @author Adrian Cole
+ */
+public class GleSYSApiMetadata extends BaseRestApiMetadata {
+   
+   /** The serialVersionUID */
+   private static final long serialVersionUID = 6725672099385580694L;
+
+   public static final TypeToken<RestContext<GleSYSApi, GleSYSAsyncApi>> CONTEXT_TOKEN = new TypeToken<RestContext<GleSYSApi, GleSYSAsyncApi>>() {
+      private static final long serialVersionUID = -5070937833892503232L;
+   };
+   
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   public GleSYSApiMetadata() {
+      this(new Builder());
+   }
+
+   protected GleSYSApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseRestApiMetadata.defaultProperties();
+      properties.setProperty("jclouds.ssh.max-retries", "5");
+      properties.setProperty("jclouds.ssh.retry-auth", "true");
+      return properties;
+   }
+
+   public static class Builder
+         extends
+         BaseRestApiMetadata.Builder {
+
+      protected Builder() {
+         super(GleSYSApi.class, GleSYSAsyncApi.class);
+         id("glesys")
+         .name("GleSYS API")
+         .identityName("Username")
+         .credentialName("API Key")
+         .documentation(URI.create("https://customer.glesys.com/api.php"))
+         .version("1")
+         .buildVersion("3.5.0")
+         .defaultEndpoint("https://api.glesys.com")
+         .defaultProperties(GleSYSApiMetadata.defaultProperties())
+         .view(TypeToken.of(ComputeServiceContext.class))
+         .defaultModules(ImmutableSet.<Class<? extends Module>>of(GleSYSComputeServiceContextModule.class, GleSYSRestClientModule.class));
+      }
+
+      @Override
+      public GleSYSApiMetadata build() {
+         return new GleSYSApiMetadata(this);
+      }
+
+      @Override
+      public Builder fromApiMetadata(ApiMetadata in) {
+         super.fromApiMetadata(in);
+         return this;
+      }
+
+   }
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncApi.java
new file mode 100644
index 0000000..fd341eb
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSAsyncApi.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys;
+
+import org.jclouds.glesys.features.ArchiveAsyncApi;
+import org.jclouds.glesys.features.DomainAsyncApi;
+import org.jclouds.glesys.features.EmailAccountAsyncApi;
+import org.jclouds.glesys.features.IpAsyncApi;
+import org.jclouds.glesys.features.ServerAsyncApi;
+import org.jclouds.rest.annotations.Delegate;
+
+/**
+ * Provides asynchronous access to GleSYS via their REST API.
+ * <p/>
+ * 
+ * @see GleSYSApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ * @author Adrian Cole
+ */
+public interface GleSYSAsyncApi {
+
+   /**
+    * Provides asynchronous access to Server features.
+    */
+   @Delegate
+   ServerAsyncApi getServerApi();
+
+   /**
+    * Provides asynchronous access to Ip Address features.
+    */
+   @Delegate
+   IpAsyncApi getIpApi();
+
+   /**
+    * Provides asynchronous access to Archive features.
+    */
+   @Delegate
+   ArchiveAsyncApi getArchiveApi();
+
+   /**
+    * Provides asynchronous access to DNS features.
+    */
+   @Delegate
+   DomainAsyncApi getDomainApi();
+
+   /**
+    * Provides asynchronous access to E-Mail features.
+    */
+   @Delegate
+   EmailAccountAsyncApi getEmailAccountApi();
+   
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java b/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java
new file mode 100644
index 0000000..fc272cc
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/GleSYSProviderMetadata.java
@@ -0,0 +1,94 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys;
+
+import static org.jclouds.compute.config.ComputeServiceProperties.TEMPLATE;
+import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONE;
+import static org.jclouds.location.reference.LocationConstants.PROPERTY_ZONES;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+
+/**
+ * Implementation of {@link org.jclouds.types.ProviderMetadata} for GleSYS.
+ * @author Adrian Cole
+ */
+public class GleSYSProviderMetadata extends BaseProviderMetadata {
+
+   /** The serialVersionUID */
+   private static final long serialVersionUID = 539076518401969165L;
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   @Override
+   public Builder toBuilder() {
+      return builder().fromProviderMetadata(this);
+   }
+
+   public GleSYSProviderMetadata() {
+      super(builder());
+   }
+
+   public GleSYSProviderMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = new Properties();
+      properties.setProperty(PROPERTY_ZONES, "Amsterdam,Falkenberg,New York City,Stockholm");
+      properties.setProperty(PROPERTY_ZONE + ".Amsterdam." + ISO3166_CODES, "NL-NH");
+      properties.setProperty(PROPERTY_ZONE + ".Falkenberg." + ISO3166_CODES, "SE-N");
+      properties.setProperty(PROPERTY_ZONE + ".New York City." + ISO3166_CODES, "US-NY");
+      properties.setProperty(PROPERTY_ZONE + ".Stockholm." + ISO3166_CODES, "SE-AB");
+      properties.setProperty(TEMPLATE, "osFamily=UBUNTU,osVersionMatches=1[012].[01][04],os64Bit=true,minRam=768");
+      return properties;
+   }
+
+   public static class Builder extends BaseProviderMetadata.Builder {
+
+      protected Builder() {
+         id("glesys")
+         .name("GleSYS")
+         .apiMetadata(new GleSYSApiMetadata())
+         .homepage(URI.create("http://www.glesys.com"))
+         .console(URI.create("https://customer.glesys.com/cloud.php"))
+         .iso3166Codes("NL-NH","SE-N","US-NY","SE-AB")
+         .endpoint("https://api.glesys.com")
+         .defaultProperties(GleSYSProviderMetadata.defaultProperties());
+      }
+
+      @Override
+      public GleSYSProviderMetadata build() {
+         return new GleSYSProviderMetadata(this);
+      }
+
+      @Override
+      public Builder fromProviderMetadata(ProviderMetadata in) {
+         super.fromProviderMetadata(in);
+         return this;
+      }
+
+   }
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
new file mode 100644
index 0000000..c42a297
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapter.java
@@ -0,0 +1,281 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.compute;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.compute.util.ComputeServiceUtils.metadataAndTagsAsCommaDelimitedValue;
+import static org.jclouds.concurrent.FutureIterables.transformParallel;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.jclouds.Constants;
+import org.jclouds.collect.FindResourceInSet;
+import org.jclouds.collect.Memoized;
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.ComputeServiceAdapter;
+import org.jclouds.compute.domain.Hardware;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.internal.VolumeImpl;
+import org.jclouds.compute.predicates.ImagePredicates;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.domain.Location;
+import org.jclouds.domain.LoginCredentials;
+import org.jclouds.glesys.GleSYSApi;
+import org.jclouds.glesys.GleSYSAsyncApi;
+import org.jclouds.glesys.compute.options.GleSYSTemplateOptions;
+import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
+import org.jclouds.glesys.domain.OSTemplate;
+import org.jclouds.glesys.domain.Server;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.glesys.domain.ServerSpec;
+import org.jclouds.glesys.options.CreateServerOptions;
+import org.jclouds.glesys.options.DestroyServerOptions;
+import org.jclouds.location.predicates.LocationPredicates;
+import org.jclouds.logging.Logger;
+import org.jclouds.predicates.RetryablePredicate;
+import org.jclouds.util.Iterables2;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/**
+ * defines the connection between the {@link GleSYSApi} implementation and
+ * the jclouds {@link ComputeService}
+ * 
+ */
+@Singleton
+public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter<ServerDetails, Hardware, OSTemplate, String> {
+
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+
+   private final GleSYSApi api;
+   private final GleSYSAsyncApi aapi;
+   private final ExecutorService userThreads;
+   private final Timeouts timeouts;
+   private final Supplier<Set<? extends Location>> locations;
+   private final Provider<String> passwordProvider;
+
+   @Inject
+   public GleSYSComputeServiceAdapter(GleSYSApi api, GleSYSAsyncApi aapi,
+         @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, Timeouts timeouts,
+         @Memoized Supplier<Set<? extends Location>> locations, @Named("PASSWORD") Provider<String> passwordProvider) {
+      this.api = checkNotNull(api, "api");
+      this.aapi = checkNotNull(aapi, "aapi");
+      this.userThreads = checkNotNull(userThreads, "userThreads");
+      this.timeouts = checkNotNull(timeouts, "timeouts");
+      this.locations = checkNotNull(locations, "locations");
+      this.passwordProvider = checkNotNull(passwordProvider, "passwordProvider");
+   }
+
+   @Override
+   public NodeAndInitialCredentials<ServerDetails> createNodeWithGroupEncodedIntoName(String group, String name,
+         Template template) {
+      checkNotNull(template, "template was null");
+      checkNotNull(template.getOptions(), "template options was null");
+      checkArgument(template.getOptions().getClass().isAssignableFrom(GleSYSTemplateOptions.class),
+            "options class %s should have been assignable from GleSYSTemplateOptions", template.getOptions().getClass());
+
+      GleSYSTemplateOptions templateOptions = template.getOptions().as(GleSYSTemplateOptions.class);
+
+      CreateServerOptions createServerOptions = new CreateServerOptions();
+      createServerOptions.ip(templateOptions.getIp());
+
+      Map<String, String> md = metadataAndTagsAsCommaDelimitedValue(template.getOptions());
+      if (md.size() > 0) {
+         String description = Joiner.on('\n').withKeyValueSeparator("=").join(md);
+         // TODO: get glesys to stop stripping out equals and commas!
+         createServerOptions.description(CryptoStreams.hex(description.getBytes(Charsets.UTF_8)));
+      }
+
+      ServerSpec.Builder<?> builder = ServerSpec.builder();
+      builder.datacenter(template.getLocation().getId());
+      builder.templateName(template.getImage().getId());
+      builder.platform(template.getHardware().getHypervisor());
+      builder.memorySizeMB(template.getHardware().getRam());
+      builder.diskSizeGB(Math.round(template.getHardware().getVolumes().get(0).getSize()));
+      builder.cpuCores((int) template.getHardware().getProcessors().get(0).getCores());
+      builder.transferGB(50);// TODO: add to template options with default value
+      ServerSpec spec = builder.build();
+
+      String password = passwordProvider.get(); // TODO: add to templateOptions
+                                                // and set if present
+
+      logger.debug(">> creating new Server spec(%s) name(%s) options(%s)", spec, name, createServerOptions);
+      ServerDetails result = api.getServerApi().createWithHostnameAndRootPassword(spec, name, password,
+            createServerOptions);
+      logger.trace("<< server(%s)", result.getId());
+
+      return new NodeAndInitialCredentials<ServerDetails>(result, result.getId() + "", LoginCredentials.builder()
+            .password(password).build());
+   }
+
+   @Singleton
+   public static class FindLocationForServerSpec extends FindResourceInSet<ServerSpec, Location> {
+
+      @Inject
+      public FindLocationForServerSpec(@Memoized Supplier<Set<? extends Location>> location) {
+         super(location);
+      }
+
+      @Override
+      public boolean matches(ServerSpec from, Location input) {
+         return input.getId().equals(from.getDatacenter());
+      }
+   }
+
+   @Override
+   public Iterable<Hardware> listHardwareProfiles() {
+      Set<? extends Location> locationsSet = locations.get();
+      ImmutableSet.Builder<Hardware> hardwareToReturn = ImmutableSet.builder();
+
+      // do this loop after dupes are filtered, else OOM
+      Set<OSTemplate> images = listImages();
+
+      for (Entry<String, AllowedArgumentsForCreateServer> platformToArgs : api.getServerApi()
+            .getAllowedArgumentsForCreateByPlatform().entrySet())
+         for (String datacenter : platformToArgs.getValue().getDataCenters())
+            for (int diskSizeGB : platformToArgs.getValue().getDiskSizesInGB())
+               for (int cpuCores : platformToArgs.getValue().getCpuCoreOptions())
+                  for (int memorySizeMB : platformToArgs.getValue().getMemorySizesInMB()) {
+                     ImmutableSet.Builder<String> templatesSupportedBuilder = ImmutableSet.builder();
+                     for (OSTemplate template : images) {
+                        if (template.getPlatform().equals(platformToArgs.getKey())
+                              && diskSizeGB >= template.getMinDiskSize() && memorySizeMB >= template.getMinMemSize())
+                           templatesSupportedBuilder.add(template.getName());
+                     }
+                     ImmutableSet<String> templatesSupported = templatesSupportedBuilder.build();
+                     if (templatesSupported.size() > 0)
+                        hardwareToReturn.add(new HardwareBuilder()
+                              .ids(String.format(
+                                    "datacenter(%s)platform(%s)cpuCores(%d)memorySizeMB(%d)diskSizeGB(%d)", datacenter,
+                                    platformToArgs.getKey(), cpuCores, memorySizeMB, diskSizeGB)).ram(memorySizeMB)
+                              .processors(ImmutableList.of(new Processor(cpuCores, 1.0)))
+                              .volumes(ImmutableList.<Volume> of(new VolumeImpl((float) diskSizeGB, true, true)))
+                              .hypervisor(platformToArgs.getKey())
+                              .location(Iterables.find(locationsSet, LocationPredicates.idEquals(datacenter)))
+                              .supportsImage(ImagePredicates.idIn(templatesSupported)).build());
+                  }
+
+      return hardwareToReturn.build();
+   }
+
+   @Override
+   public Set<OSTemplate> listImages() {
+      return api.getServerApi().listTemplates().toImmutableSet();
+   }
+   
+   // cheat until we have a getTemplate command
+   @Override
+   public OSTemplate getImage(final String id) {
+      return Iterables.find(listImages(), new Predicate<OSTemplate>(){
+
+         @Override
+         public boolean apply(OSTemplate input) {
+            return input.getName().equals(id);
+         }
+         
+      }, null);
+   }
+   
+   @Override
+   public Iterable<ServerDetails> listNodes() {
+      return Iterables2.concreteCopy(transformParallel(api.getServerApi().list(), new Function<Server, Future<? extends ServerDetails>>() {
+         @Override
+         public Future<ServerDetails> apply(Server from) {
+            return aapi.getServerApi().get(from.getId());
+         }
+
+      }, userThreads, null, logger, "server details"));
+   }
+
+   @Override
+   public Set<String> listLocations() {
+      return ImmutableSet.copyOf(Iterables.concat(Iterables.transform(api.getServerApi()
+            .getAllowedArgumentsForCreateByPlatform().values(),
+            new Function<AllowedArgumentsForCreateServer, Set<String>>() {
+
+               @Override
+               public Set<String> apply(AllowedArgumentsForCreateServer arg0) {
+                  return arg0.getDataCenters();
+               }
+
+            })));
+   }
+
+   @Override
+   public ServerDetails getNode(String id) {
+      return api.getServerApi().get(id);
+   }
+
+   @Override
+   public void destroyNode(String id) {
+      new RetryablePredicate<String>(new Predicate<String>() {
+
+         @Override
+         public boolean apply(String arg0) {
+            try {
+               api.getServerApi().destroy(arg0, DestroyServerOptions.Builder.discardIp());
+               return true;
+            } catch (IllegalStateException e) {
+               return false;
+            }
+         }
+
+      }, timeouts.nodeTerminated).apply(id);
+   }
+
+   @Override
+   public void rebootNode(String id) {
+      api.getServerApi().reboot(id);
+   }
+
+   @Override
+   public void resumeNode(String id) {
+      api.getServerApi().start(id);
+   }
+
+   @Override
+   public void suspendNode(String id) {
+      api.getServerApi().stop(id);
+   }
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/compute/config/GleSYSComputeServiceContextModule.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/DatacenterToLocation.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/DatacenterToLocation.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/DatacenterToLocation.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/DatacenterToLocation.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/FindLocationForServerSpec.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/FindLocationForServerSpec.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/FindLocationForServerSpec.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/FindLocationForServerSpec.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/OSTemplateToImage.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/OSTemplateToImage.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/OSTemplateToImage.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/OSTemplateToImage.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java
new file mode 100644
index 0000000..670dd61
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageName.java
@@ -0,0 +1,92 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.compute.functions;
+
+import static com.google.common.base.Predicates.containsPattern;
+
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.domain.OsFamilyVersion64Bit;
+import org.jclouds.compute.util.ComputeServiceUtils;
+
+import com.google.common.base.Function;
+
+/**
+ * Defaults to version null and 64bit, if the operating system is unrecognized
+ * and the pattern "32bit" isn't in the string.
+ * 
+ * @author Adrian Cole
+ * 
+ */
+@Singleton
+public class ParseOsFamilyVersion64BitFromImageName implements Function<String, OsFamilyVersion64Bit> {
+   private final Map<OsFamily, Map<String, String>> osVersionMap;
+
+   @Inject
+   public ParseOsFamilyVersion64BitFromImageName(Map<OsFamily, Map<String, String>> osVersionMap) {
+      this.osVersionMap = osVersionMap;
+   }
+
+   // ex Debian 6.0 64-bit
+   // ex. Ubuntu 10.04 LTS 32-bit
+   public static final Pattern OSFAMILY_VERSION = Pattern
+         .compile("([^ ]+).*[ -]([0-9.]+)( LTS)?( [36][24]-bit)?( x[68][46])?$");
+   public static final Pattern OSFAMILY = Pattern.compile("([^ ]+).*$");
+
+   @Override
+   public OsFamilyVersion64Bit apply(String input) {
+      boolean is64Bit = containsPattern("64").apply(input);
+      String version = "";
+
+      if (input.indexOf("Windows") != -1) {
+         Matcher matcher = Pattern.compile(".*(20[01][0-9] R[1-9]).*").matcher(input);
+         if (matcher.find()) {
+            version = matcher.group(1);
+         } else {
+            matcher = Pattern.compile(".*(20[01][0-9]).*").matcher(input);
+            if (matcher.find())
+               version = matcher.group(1);
+         }
+         return new OsFamilyVersion64Bit(OsFamily.WINDOWS, osVersionMap.get(OsFamily.WINDOWS).get(version), is64Bit);
+      }
+      Matcher osFamilyVersionMatcher = OSFAMILY_VERSION.matcher(input);
+      if (osFamilyVersionMatcher.find()) {
+         OsFamily fam = OsFamily.fromValue(osFamilyVersionMatcher.group(1).toLowerCase());
+         if (fam == OsFamily.UNRECOGNIZED ) {
+            return new OsFamilyVersion64Bit(OsFamily.UNRECOGNIZED, version, is64Bit);
+         }
+         return new OsFamilyVersion64Bit(fam, ComputeServiceUtils.parseVersionOrReturnEmptyString(fam,
+               osFamilyVersionMatcher.group(2), osVersionMap), is64Bit);
+      } else {
+         Matcher osFamilyMatcher = OSFAMILY.matcher(input);
+         OsFamily fam = OsFamily.UNRECOGNIZED;
+         if (osFamilyMatcher.find()) {
+            fam = OsFamily.fromValue(osFamilyMatcher.group(1).toLowerCase());
+         }
+         return new OsFamilyVersion64Bit(fam, version, is64Bit);
+      }
+
+   }
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java
new file mode 100644
index 0000000..bc83ba7
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadata.java
@@ -0,0 +1,164 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.compute.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
+
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.annotation.Resource;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.jclouds.collect.FindResourceInSet;
+import org.jclouds.collect.Memoized;
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.Image;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.internal.VolumeImpl;
+import org.jclouds.compute.functions.GroupNamingConvention;
+import org.jclouds.compute.reference.ComputeServiceConstants;
+import org.jclouds.crypto.CryptoStreams;
+import org.jclouds.domain.Location;
+import org.jclouds.glesys.domain.Ip;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.logging.Logger;
+import org.jclouds.util.InetAddresses2.IsPrivateIPAddress;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+/**
+ * @author Adrian Cole
+ */
+@Singleton
+public class ServerDetailsToNodeMetadata implements Function<ServerDetails, NodeMetadata> {
+   @Resource
+   @Named(ComputeServiceConstants.COMPUTE_LOGGER)
+   protected Logger logger = Logger.NULL;
+   public static final Map<ServerDetails.State, Status> serverStateToNodeStatus = ImmutableMap
+         .<ServerDetails.State, Status> builder().put(ServerDetails.State.STOPPED, Status.SUSPENDED)
+         .put(ServerDetails.State.LOCKED, Status.PENDING)
+         .put(ServerDetails.State.RUNNING, Status.RUNNING)
+         .put(ServerDetails.State.UNRECOGNIZED, Status.UNRECOGNIZED).build();
+
+   protected final Supplier<Set<? extends Image>> images;
+   protected final FindLocationForServerDetails findLocationForServerDetails;
+   protected final GroupNamingConvention nodeNamingConvention;
+
+   private static class FindImageForServer implements Predicate<Image> {
+      private final ServerDetails instance;
+
+      private FindImageForServer(ServerDetails instance) {
+         this.instance = instance;
+      }
+
+      @Override
+      public boolean apply(Image input) {
+         return input.getProviderId().equals(instance.getTemplateName());
+      }
+   }
+
+   @Inject
+   ServerDetailsToNodeMetadata(FindLocationForServerDetails findLocationForServerDetails,
+         @Memoized Supplier<Set<? extends Image>> images,
+         GroupNamingConvention.Factory namingConvention) {
+      this.nodeNamingConvention = checkNotNull(namingConvention, "namingConvention").createWithoutPrefix();
+      this.findLocationForServerDetails = checkNotNull(findLocationForServerDetails, "findLocationForServerDetails");
+      this.images = checkNotNull(images, "images");
+   }
+
+   @Override
+   public NodeMetadata apply(ServerDetails from) {
+      NodeMetadataBuilder builder = new NodeMetadataBuilder();
+      builder.ids(from.getId() + "");
+      builder.name(from.getHostname());
+      builder.hostname(from.getHostname());
+      Location location = findLocationForServerDetails.apply(from);
+      checkState(location != null, "no location matched ServerDetails %s", from);
+      builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getHostname()));
+      
+      // TODO: get glesys to stop stripping out equals and commas!
+      if (!isNullOrEmpty(from.getDescription()) && from.getDescription().matches("^[0-9A-Fa-f]+$")) {
+         String decoded = new String(CryptoStreams.hex(from.getDescription()), Charsets.UTF_8);
+         addMetadataAndParseTagsFromCommaDelimitedValue(builder,
+                  Splitter.on('\n').withKeyValueSeparator("=").split(decoded));
+      }
+      builder.imageId(from.getTemplateName() + "");
+      builder.operatingSystem(parseOperatingSystem(from));
+      builder.hardware(new HardwareBuilder().ids(from.getId() + "").ram(from.getMemorySizeMB())
+            .processors(ImmutableList.of(new Processor(from.getCpuCores(), 1.0)))
+            .volumes(ImmutableList.<Volume> of(new VolumeImpl((float) from.getDiskSizeGB(), true, true)))
+            .hypervisor(from.getPlatform()).build());
+      builder.status(serverStateToNodeStatus.get(from.getState()));
+      Iterable<String> addresses = Iterables.filter(Iterables.transform(from.getIps(), new Function<Ip, String>() {
+
+         @Override
+         public String apply(Ip arg0) {
+            return Strings.emptyToNull(arg0.getIp());
+         }
+
+      }), Predicates.notNull());
+      builder.publicAddresses(Iterables.filter(addresses, Predicates.not(IsPrivateIPAddress.INSTANCE)));
+      builder.privateAddresses(Iterables.filter(addresses, IsPrivateIPAddress.INSTANCE));
+      return builder.build();
+   }
+
+   protected OperatingSystem parseOperatingSystem(ServerDetails from) {
+      try {
+         return Iterables.find(images.get(), new FindImageForServer(from)).getOperatingSystem();
+      } catch (NoSuchElementException e) {
+         logger.debug("could not find a matching image for server %s", from);
+      }
+      return null;
+   }
+
+   @Singleton
+   public static class FindLocationForServerDetails extends FindResourceInSet<ServerDetails, Location> {
+
+      @Inject
+      public FindLocationForServerDetails(@Memoized Supplier<Set<? extends Location>> location) {
+         super(location);
+      }
+
+      @Override
+      public boolean matches(ServerDetails from, Location input) {
+         return input.getId().equals(from.getDatacenter());
+      }
+   }
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerSpecToHardware.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerSpecToHardware.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerSpecToHardware.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/compute/functions/ServerSpecToHardware.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java
new file mode 100644
index 0000000..3ef5ffa
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptions.java
@@ -0,0 +1,183 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.compute.options;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.Map;
+
+import org.jclouds.compute.ComputeService;
+import org.jclouds.compute.options.TemplateOptions;
+import org.jclouds.glesys.features.ServerApi;
+
+import com.google.common.net.InetAddresses;
+
+/**
+ * Contains options supported by the
+ * {@link ComputeService#createNodesInGroup(String, int, TemplateOptions)} and
+ * {@link ComputeService#createNodesInGroup(String, int, TemplateOptions)} operations on the
+ * <em>glesys</em> provider.
+ * 
+ * <h2>Usage</h2> The recommended way to instantiate a {@link GleSYSTemplateOptions} object is to
+ * statically import {@code GleSYSTemplateOptions.*} and invoke a static creation method followed by
+ * an instance mutator (if needed):
+ * <p>
+ * 
+ * <pre>
+ * import static org.jclouds.compute.options.GleSYSTemplateOptions.Builder.*;
+ * ComputeService api = // get connection
+ * templateBuilder.options(inboundPorts(22, 80, 8080, 443));
+ * Set&lt;? extends NodeMetadata&gt; set = api.createNodesInGroup(tag, 2, templateBuilder.build());
+ * </pre>
+ * 
+ * @author Adrian Cole
+ */
+public class GleSYSTemplateOptions extends TemplateOptions implements Cloneable {
+
+   protected String ip = "any";
+
+   @Override
+   public GleSYSTemplateOptions clone() {
+      GleSYSTemplateOptions options = new GleSYSTemplateOptions();
+      copyTo(options);
+      return options;
+   }
+
+   @Override
+   public void copyTo(TemplateOptions to) {
+      super.copyTo(to);
+      if (to instanceof GleSYSTemplateOptions) {
+         GleSYSTemplateOptions eTo = GleSYSTemplateOptions.class.cast(to);
+         eTo.ip(ip);
+      }
+   }
+
+   /**
+    * 
+    * @see ServerApi#createWithHostnameAndRootPassword
+    * @see InetAddresses#isInetAddress
+    */
+   public TemplateOptions ip(String ip) {
+      if (ip != null)
+         checkArgument("any".equals(ip) || InetAddresses.isInetAddress(ip), "ip %s is not valid", ip);
+      this.ip = ip;
+      return this;
+   }
+
+   public String getIp() {
+      return ip;
+   }
+
+   public static final GleSYSTemplateOptions NONE = new GleSYSTemplateOptions();
+
+   public static class Builder {
+
+      /**
+       * @see #ip
+       */
+      public static GleSYSTemplateOptions ip(String ip) {
+         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
+         return GleSYSTemplateOptions.class.cast(options.ip(ip));
+      }
+
+      // methods that only facilitate returning the correct object type
+
+      /**
+       * @see TemplateOptions#inboundPorts(int...)
+       */
+      public static GleSYSTemplateOptions inboundPorts(int... ports) {
+         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
+         return GleSYSTemplateOptions.class.cast(options.inboundPorts(ports));
+      }
+
+      /**
+       * @see TemplateOptions#blockOnPort(int, int)
+       */
+      public static GleSYSTemplateOptions blockOnPort(int port, int seconds) {
+         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
+         return GleSYSTemplateOptions.class.cast(options.blockOnPort(port, seconds));
+      }
+      
+      /**
+       * @see TemplateOptions#userMetadata(Map)
+       */
+      public static GleSYSTemplateOptions userMetadata(Map<String, String> userMetadata) {
+         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
+         return GleSYSTemplateOptions.class.cast(options.userMetadata(userMetadata));
+      }
+
+      /**
+       * @see TemplateOptions#userMetadata(String, String)
+       */
+      public static GleSYSTemplateOptions userMetadata(String key, String value) {
+         GleSYSTemplateOptions options = new GleSYSTemplateOptions();
+         return GleSYSTemplateOptions.class.cast(options.userMetadata(key, value));
+      }
+   }
+
+   // methods that only facilitate returning the correct object type
+
+   /**
+    * @see TemplateOptions#blockOnPort(int, int)
+    */
+   @Override
+   public GleSYSTemplateOptions blockOnPort(int port, int seconds) {
+      return GleSYSTemplateOptions.class.cast(super.blockOnPort(port, seconds));
+   }
+
+   /**
+    * @see TemplateOptions#inboundPorts(int...)
+    */
+   @Override
+   public GleSYSTemplateOptions inboundPorts(int... ports) {
+      return GleSYSTemplateOptions.class.cast(super.inboundPorts(ports));
+   }
+
+   /**
+    * @see TemplateOptions#authorizePublicKey(String)
+    */
+   @Override
+   public GleSYSTemplateOptions authorizePublicKey(String publicKey) {
+      return GleSYSTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
+   }
+
+   /**
+    * @see TemplateOptions#installPrivateKey(String)
+    */
+   @Override
+   public GleSYSTemplateOptions installPrivateKey(String privateKey) {
+      return GleSYSTemplateOptions.class.cast(super.installPrivateKey(privateKey));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public GleSYSTemplateOptions userMetadata(Map<String, String> userMetadata) {
+      return GleSYSTemplateOptions.class.cast(super.userMetadata(userMetadata));
+   }
+
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public GleSYSTemplateOptions userMetadata(String key, String value) {
+      return GleSYSTemplateOptions.class.cast(super.userMetadata(key, value));
+   }
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSParserModule.java b/providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSParserModule.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/config/GleSYSParserModule.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSParserModule.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java b/providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java
new file mode 100644
index 0000000..ffb41c5
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/config/GleSYSRestClientModule.java
@@ -0,0 +1,93 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.config;
+
+import java.util.Map;
+
+import org.jclouds.glesys.GleSYSApi;
+import org.jclouds.glesys.GleSYSAsyncApi;
+import org.jclouds.glesys.features.ArchiveApi;
+import org.jclouds.glesys.features.ArchiveAsyncApi;
+import org.jclouds.glesys.features.DomainApi;
+import org.jclouds.glesys.features.DomainAsyncApi;
+import org.jclouds.glesys.features.EmailAccountApi;
+import org.jclouds.glesys.features.EmailAccountAsyncApi;
+import org.jclouds.glesys.features.IpApi;
+import org.jclouds.glesys.features.IpAsyncApi;
+import org.jclouds.glesys.features.ServerApi;
+import org.jclouds.glesys.features.ServerAsyncApi;
+import org.jclouds.glesys.handlers.GleSYSErrorHandler;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpRetryHandler;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.location.suppliers.ImplicitLocationSupplier;
+import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstZone;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.config.RestClientModule;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Scopes;
+
+/**
+ * Configures the GleSYS connection.
+ * 
+ * @author Adrian Cole
+ */
+@ConfiguresRestClient
+public class GleSYSRestClientModule extends RestClientModule<GleSYSApi, GleSYSAsyncApi> {
+
+   public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder()//
+         .put(ServerApi.class, ServerAsyncApi.class)//
+         .put(IpApi.class, IpAsyncApi.class)//
+         .put(ArchiveApi.class, ArchiveAsyncApi.class)//
+         .put(DomainApi.class, DomainAsyncApi.class)//
+         .put(EmailAccountApi.class, EmailAccountAsyncApi.class)//
+         .build();
+
+   public GleSYSRestClientModule() {
+      super(DELEGATE_MAP);
+   }
+
+   @Override
+   protected void configure() {
+      install(new GleSYSParserModule());
+      super.configure();
+   }
+
+   @Override
+   protected void bindErrorHandlers() {
+      bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(GleSYSErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(GleSYSErrorHandler.class);
+      bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(GleSYSErrorHandler.class);
+   }
+
+   @Override
+   protected void bindRetryHandlers() {
+      bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);
+   }
+   
+   @Override
+   protected void installLocations() {
+      super.installLocations();
+      bind(ImplicitLocationSupplier.class).to(OnlyLocationOrFirstZone.class).in(Scopes.SINGLETON);
+   }
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/AllowedArgumentsForCreateServer.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/AllowedArgumentsForCreateServer.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/AllowedArgumentsForCreateServer.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/AllowedArgumentsForCreateServer.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/Archive.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java
new file mode 100644
index 0000000..493532d
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ArchiveAllowedArguments.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.util.List;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * The allowed arguments for archive manipulation, such as archivesize
+ *
+ * @author Adam Lowe
+ * @see <a href= "https://customer.glesys.com/api.php?a=doc#archive_allowedarguments" />
+ */
+public class ArchiveAllowedArguments {
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromArchiveAllowedArguments(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected List<Integer> archiveSizes = ImmutableList.of();
+
+      /**
+       * @see ArchiveAllowedArguments#getSizes()
+       */
+      public T archiveSizes(List<Integer> archiveSizes) {
+         this.archiveSizes = ImmutableList.copyOf(checkNotNull(archiveSizes, "archiveSizes"));
+         return self();
+      }
+
+      public T archiveSizes(Integer... in) {
+         return archiveSizes(ImmutableList.copyOf(in));
+      }
+
+      public ArchiveAllowedArguments build() {
+         return new ArchiveAllowedArguments(archiveSizes);
+      }
+
+      public T fromArchiveAllowedArguments(ArchiveAllowedArguments in) {
+         return this.archiveSizes(in.getSizes());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final List<Integer> archiveSizes;
+
+   @ConstructorProperties({
+         "archivesize"
+   })
+   protected ArchiveAllowedArguments(List<Integer> archiveSizes) {
+      this.archiveSizes = ImmutableList.copyOf(checkNotNull(archiveSizes, "archiveSizes"));
+   }
+
+   /**
+    * @return the list of allowed archive sizes, in GB
+    */
+   public List<Integer> getSizes() {
+      return this.archiveSizes;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(archiveSizes);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      ArchiveAllowedArguments that = ArchiveAllowedArguments.class.cast(obj);
+      return Objects.equal(this.archiveSizes, that.archiveSizes);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper("")
+            .add("archiveSizes", archiveSizes);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/Console.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/Console.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/Console.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/Console.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/Cost.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/Cost.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/Cost.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/Cost.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java
new file mode 100644
index 0000000..59774e9
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/domain/Domain.java
@@ -0,0 +1,309 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.util.Date;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * Domain data for a Glesys account.
+ *
+ * @author Adam Lowe
+ * @see <a href= "https://customer.glesys.com/api.php?a=doc#domain_list" />
+ */
+public class Domain {
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromDomain(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected String domainName;
+      protected Date createTime;
+      protected int recordCount;
+      protected boolean useGlesysNameServer;
+      protected String primaryNameServer;
+      protected String responsiblePerson;
+      protected int ttl;
+      protected int refresh;
+      protected int retry;
+      protected int expire;
+      protected int minimum;
+
+      /**
+       * @see Domain#getName()
+       */
+      public T domainName(String domainName) {
+         this.domainName = checkNotNull(domainName, "domainName");
+         return self();
+      }
+
+      /**
+       * @see Domain#getCreateTime()
+       */
+      public T createTime(Date createTime) {
+         this.createTime = createTime;
+         return self();
+      }
+
+      /**
+       * @see Domain#getRecordCount()
+       */
+      public T recordCount(int recordCount) {
+         this.recordCount = recordCount;
+         return self();
+      }
+
+      /**
+       * @see Domain#isUseGlesysNameServer()
+       */
+      public T useGlesysNameServer(boolean useGlesysNameServer) {
+         this.useGlesysNameServer = useGlesysNameServer;
+         return self();
+      }
+
+      /**
+       * @see Domain#getPrimaryNameServer()
+       */
+      public T primaryNameServer(String primaryNameServer) {
+         this.primaryNameServer = primaryNameServer;
+         return self();
+      }
+
+      /**
+       * @see Domain#getResponsiblePerson()
+       */
+      public T responsiblePerson(String responsiblePerson) {
+         this.responsiblePerson = responsiblePerson;
+         return self();
+      }
+
+      /**
+       * @see Domain#getTtl()
+       */
+      public T ttl(int ttl) {
+         this.ttl = ttl;
+         return self();
+      }
+
+      /**
+       * @see Domain#getRefresh()
+       */
+      public T refresh(int refresh) {
+         this.refresh = refresh;
+         return self();
+      }
+
+      /**
+       * @see Domain#getRetry()
+       */
+      public T retry(int retry) {
+         this.retry = retry;
+         return self();
+      }
+
+      /**
+       * @see Domain#getExpire()
+       */
+      public T expire(int expire) {
+         this.expire = expire;
+         return self();
+      }
+
+      /**
+       * @see Domain#getMinimum()
+       */
+      public T minimum(int minimum) {
+         this.minimum = minimum;
+         return self();
+      }
+
+      public Domain build() {
+         return new Domain(domainName, createTime, recordCount, new GleSYSBoolean(useGlesysNameServer), primaryNameServer, responsiblePerson, ttl, refresh, retry, expire, minimum);
+      }
+
+      public T fromDomain(Domain in) {
+         return this.domainName(in.getName())
+               .createTime(in.getCreateTime())
+               .recordCount(in.getRecordCount())
+               .useGlesysNameServer(in.isUseGlesysNameServer())
+               .primaryNameServer(in.getPrimaryNameServer())
+               .responsiblePerson(in.getResponsiblePerson())
+               .ttl(in.getTtl())
+               .refresh(in.getRefresh())
+               .retry(in.getRetry())
+               .expire(in.getExpire());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final String domainName;
+   private final Date createTime;
+   private final int recordCount;
+   private final boolean useGlesysNameServer;
+   private final String primaryNameServer;
+   private final String responsiblePerson;
+   private final int ttl;
+   private final int refresh;
+   private final int retry;
+   private final int expire;
+   private final int minimum;
+
+   @ConstructorProperties({
+         "domainname", "createtime", "recordcount", "usingglesysnameserver", "primarynameserver", "responsibleperson",
+         "ttl", "refresh", "retry", "expire", "minimum"
+   })
+   protected Domain(String domainName, @Nullable Date createTime, int recordCount, GleSYSBoolean useGlesysNameServer,
+                    @Nullable String primaryNameServer, @Nullable String responsiblePerson,
+                    int ttl, int refresh, int retry, int expire, int minimum) {
+      this.domainName = checkNotNull(domainName, "domainName");
+      this.createTime = createTime;
+      this.recordCount = recordCount;
+      this.useGlesysNameServer = checkNotNull(useGlesysNameServer, "useGlesysNameServer").getValue();
+      this.primaryNameServer = primaryNameServer;
+      this.responsiblePerson = responsiblePerson;
+      this.ttl = ttl;
+      this.refresh = refresh;
+      this.retry = retry;
+      this.expire = expire;
+      this.minimum = minimum;
+   }
+
+   /**
+    * @return the domain name, ex. "jclouds.org"
+    */
+   public String getName() {
+      return this.domainName;
+   }
+
+   /**
+    * @return the date the domain was registered with GleSYS
+    */
+   public Date getCreateTime() {
+      return this.createTime;
+   }
+
+   /**
+    * @return the number of DNS records for this domain
+    */
+   public int getRecordCount() {
+      return this.recordCount;
+   }
+
+   /**
+    * @return true if a GleSYS nameserver holds the records
+    */
+   public boolean isUseGlesysNameServer() {
+      return this.useGlesysNameServer;
+   }
+
+   @Nullable
+   public String getPrimaryNameServer() {
+      return primaryNameServer;
+   }
+
+   /**
+    * The E-mail address of the person responsible for this domain (reformatted with '.' at end).
+    */
+   @Nullable
+   public String getResponsiblePerson() {
+      return responsiblePerson;
+   }
+
+   /**
+    * TTL (time to live). The number of seconds a domain name is cached locally before expiration and return to authoritative nameServers for updates
+    */
+   public int getTtl() {
+      return ttl;
+   }
+
+   /**
+    * The number of seconds between update requests from secondary and slave name servers
+    */
+   public int getRefresh() {
+      return refresh;
+   }
+
+
+   /**
+    * The number of seconds the secondary/slave will wait before retrying when the last attempt failed
+    */
+   public int getRetry() {
+      return retry;
+   }
+
+   /**
+    * The number of seconds a master or slave will wait before considering the data stale if it cannot reach the primary name server
+    */
+   public int getExpire() {
+      return expire;
+   }
+
+   /**
+    * The minimum/default TTL if the domain does not specify ttl
+    *
+    * @see #getTtl()
+    */
+   public int getMinimum() {
+      return minimum;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(domainName);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      Domain that = Domain.class.cast(obj);
+      return Objects.equal(this.domainName, that.domainName);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper("")
+            .add("domainName", domainName).add("createTime", createTime).add("recordCount", recordCount).add("useGlesysNameServer", useGlesysNameServer);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java
new file mode 100644
index 0000000..2a35291
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/domain/DomainRecord.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * DNS record data.
+ *
+ * @author Adam Lowe
+ * @see <a href= "https://customer.glesys.com/api.php?a=doc#domain_list_records" />
+ */
+public class DomainRecord {
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromDomainRecord(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected String id;
+      protected String domainname;
+      protected String host;
+      protected String type;
+      protected String data;
+      protected int ttl;
+
+      /**
+       * @see DomainRecord#getId()
+       */
+      public T id(String id) {
+         this.id = checkNotNull(id, "id");
+         return self();
+      }
+
+      /**
+       * @see DomainRecord#getname()
+       */
+      public T domainname(String domainname) {
+         this.domainname = checkNotNull(domainname, "domainname");
+         return self();
+      }
+
+      /**
+       * @see DomainRecord#getHost()
+       */
+      public T host(String host) {
+         this.host = checkNotNull(host, "host");
+         return self();
+      }
+
+      /**
+       * @see DomainRecord#getType()
+       */
+      public T type(String type) {
+         this.type = checkNotNull(type, "type");
+         return self();
+      }
+
+      /**
+       * @see DomainRecord#getData()
+       */
+      public T data(String data) {
+         this.data = checkNotNull(data, "data");
+         return self();
+      }
+
+      /**
+       * @see DomainRecord#getTtl()
+       */
+      public T ttl(int ttl) {
+         this.ttl = ttl;
+         return self();
+      }
+
+      public DomainRecord build() {
+         return new DomainRecord(id, domainname, host, type, data, ttl);
+      }
+
+      public T fromDomainRecord(DomainRecord in) {
+         return this.id(in.getId())
+               .domainname(in.getname())
+               .host(in.getHost())
+               .type(in.getType())
+               .data(in.getData())
+               .ttl(in.getTtl());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final String id;
+   private final String domainname;
+   private final String host;
+   private final String type;
+   private final String data;
+   private final int ttl;
+
+   @ConstructorProperties({
+         "recordid", "domainname", "host", "type", "data", "ttl"
+   })
+   protected DomainRecord(@Nullable String id, String domainname, String host, String type, @Nullable String data, int ttl) {
+      this.id = id;
+      this.domainname = checkNotNull(domainname, "domainname");
+      this.host = checkNotNull(host, "host");
+      this.type = checkNotNull(type, "type");
+      this.data = data;
+      this.ttl = ttl;
+   }
+
+   /**
+    * @return the id of the record used to modify it via the API
+    * @see org.jclouds.glesys.features.DomainApi
+    */
+   public String getId() {
+      return this.id;
+   }
+
+   /**
+    * @return the zone content of the record
+    */
+   public String getname() {
+      return this.domainname;
+   }
+
+   /**
+    * @return the host content of the record
+    */
+   public String getHost() {
+      return this.host;
+   }
+
+   /**
+    * @return the type of the record, ex. "A"
+    */
+   public String getType() {
+      return this.type;
+   }
+
+   /**
+    * @return the data content of the record
+    */
+   @Nullable
+   public String getData() {
+      return this.data;
+   }
+
+   /**
+    * @return the TTL/Time-to-live for the record
+    */
+   public int getTtl() {
+      return this.ttl;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(id);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      DomainRecord that = DomainRecord.class.cast(obj);
+      return Objects.equal(this.id, that.id);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper("")
+            .add("id", id).add("domainname", domainname).add("host", host).add("type", type).add("data", data)
+            .add("ttl", ttl);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailAccount.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailAccount.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailAccount.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailAccount.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailAlias.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailAlias.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailAlias.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailAlias.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java
new file mode 100644
index 0000000..45c3c3f
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverview.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+import java.util.Set;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Structure containing all information about e-mail addresses for a GleSYS account
+ *
+ * @author Adam Lowe
+ * @see <a href="https://customer.glesys.com/api.php?a=doc#email_overview" />
+ */
+//TODO: find a better name for this class
+@Beta
+public class EmailOverview {
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromEmailOverview(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected EmailOverviewSummary summary;
+      protected Set<EmailOverviewDomain> domains = ImmutableSet.of();
+
+      /**
+       * @see EmailOverview#getSummary()
+       */
+      public T summary(EmailOverviewSummary summary) {
+         this.summary = checkNotNull(summary, "summary");
+         return self();
+      }
+
+      /**
+       * @see EmailOverview#gets()
+       */
+      public T domains(Set<EmailOverviewDomain> domains) {
+         this.domains = ImmutableSet.copyOf(checkNotNull(domains, "domains"));
+         return self();
+      }
+
+      public T domains(EmailOverviewDomain... in) {
+         return domains(ImmutableSet.copyOf(in));
+      }
+
+      public EmailOverview build() {
+         return new EmailOverview(summary, domains);
+      }
+
+      public T fromEmailOverview(EmailOverview in) {
+         return this.summary(in.getSummary()).domains(in.gets());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final EmailOverviewSummary summary;
+   private final Set<EmailOverviewDomain> domains;
+
+   @ConstructorProperties({
+         "summary", "domains"
+   })
+   protected EmailOverview(EmailOverviewSummary summary, Set<EmailOverviewDomain> domains) {
+      this.summary = checkNotNull(summary, "summary");
+      this.domains = ImmutableSet.copyOf(checkNotNull(domains, "domains"));
+   }
+
+   /**
+    * @return summary information about the account
+    */
+   public EmailOverviewSummary getSummary() {
+      return this.summary;
+   }
+
+   /**
+    * @return the set of detailed information about the e-mail addresses and aliases for each domain
+    */
+   public Set<EmailOverviewDomain> gets() {
+      return this.domains;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(summary, domains);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      EmailOverview that = EmailOverview.class.cast(obj);
+      return Objects.equal(this.summary, that.summary)
+            && Objects.equal(this.domains, that.domains);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper("")
+            .add("summary", summary).add("domains", domains);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java
new file mode 100644
index 0000000..bbf9308
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewDomain.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * Detailed information about e-mail settings for a single domain
+ *
+ * @author Adam Lowe
+ * @see <a href="https://customer.glesys.com/api.php?a=doc#email_overview" />
+ */
+@Beta
+public class EmailOverviewDomain {
+
+   public static Builder<?> builder() {
+      return new ConcreteBuilder();
+   }
+
+   public Builder<?> toBuilder() {
+      return new ConcreteBuilder().fromEmailOverviewDomain(this);
+   }
+
+   public static abstract class Builder<T extends Builder<T>> {
+      protected abstract T self();
+
+      protected String domain;
+      protected int accounts;
+      protected int aliases;
+
+      /**
+       * @see EmailOverviewDomain#get()
+       */
+      public T domain(String domain) {
+         this.domain = checkNotNull(domain, "domain");
+         return self();
+      }
+
+      /**
+       * @see EmailOverviewDomain#getAccounts()
+       */
+      public T accounts(int accounts) {
+         this.accounts = accounts;
+         return self();
+      }
+
+      /**
+       * @see EmailOverviewDomain#getAliases()
+       */
+      public T aliases(int aliases) {
+         this.aliases = aliases;
+         return self();
+      }
+
+      public EmailOverviewDomain build() {
+         return new EmailOverviewDomain(domain, accounts, aliases);
+      }
+
+      public T fromEmailOverviewDomain(EmailOverviewDomain in) {
+         return this.domain(in.get()).accounts(in.getAccounts()).aliases(in.getAliases());
+      }
+   }
+
+   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
+      @Override
+      protected ConcreteBuilder self() {
+         return this;
+      }
+   }
+
+   private final String domain;
+   private final int accounts;
+   private final int aliases;
+
+   @ConstructorProperties({
+         "domainname", "accounts", "aliases"
+   })
+   protected EmailOverviewDomain(String domain, int accounts, int aliases) {
+      this.domain = checkNotNull(domain, "domain");
+      this.accounts = accounts;
+      this.aliases = aliases;
+   }
+
+   /** @return the domain name */
+   public String get() {
+      return this.domain;
+   }
+
+   /** @return the number of e-mail accounts in the domain */
+   public int getAccounts() {
+      return this.accounts;
+   }
+
+   /** @return the number of e-mail aliases in the domain */
+   public int getAliases() {
+      return this.aliases;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(domain);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (obj == null || getClass() != obj.getClass()) return false;
+      EmailOverviewDomain that = EmailOverviewDomain.class.cast(obj);
+      return Objects.equal(this.domain, that.domain);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper("").add("domain", domain).add("accounts", accounts).add("aliases", aliases);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailOverviewSummary.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailQuota.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailQuota.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/EmailQuota.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/EmailQuota.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/GleSYSBoolean.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/GleSYSBoolean.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/GleSYSBoolean.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/GleSYSBoolean.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/Ip.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/Ip.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/Ip.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/Ip.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/IpDetails.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/IpDetails.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/IpDetails.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/IpDetails.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/OSTemplate.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/OSTemplate.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/OSTemplate.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/OSTemplate.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceStatus.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceStatus.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceStatus.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceStatus.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsage.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsage.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsage.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsage.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsageInfo.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsageInfo.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsageInfo.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsageInfo.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsageValue.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsageValue.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsageValue.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ResourceUsageValue.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/Server.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/Server.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/Server.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/Server.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerDetails.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerLimit.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerLimit.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerLimit.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerLimit.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerSpec.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerStatus.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java b/providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/domain/ServerUptime.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveApi.java
new file mode 100644
index 0000000..d50417f
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveApi.java
@@ -0,0 +1,93 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.glesys.domain.Archive;
+import org.jclouds.glesys.domain.ArchiveAllowedArguments;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * Provides synchronous access to Archive requests.
+ * <p/>
+ *
+ * @author Adam Lowe
+ * @see ArchiveAsyncApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface ArchiveApi {
+
+   /**
+    * Lists all active disks on this account.
+    */
+   FluentIterable<Archive> list();
+
+   /**
+    * Get detailed information about an archive volume.
+    *
+    * @param username the username associated with the archive
+    * @return the archive information or null if not found
+    */
+   Archive get(String username);
+
+   /**
+    * Create a new backup volume.
+    *
+    * @param username the archive username, this must be prefixed by Glesys account name (in lower case) and an 
+    *                 underscore, ex. "c100005_archive1"
+    * @param password the new password
+    * @param size     the new size required in GB
+    */
+   Archive createWithCredentialsAndSize(String username, String password, int size);
+
+   /**
+    * Delete an archive volume. All files on the volume
+    *
+    * @param username the username associated with the archive
+    */
+   void delete(String username);
+
+   /**
+    * Resize an archive volume. It is only possible to upgrade the size of the disk. Downgrading is currently not
+    * supported. If you need to downgrade, please create a new volume and transfer all data to the new volume.
+    * Then delete the old volume.
+    *
+    * @param username the username associated with the archive
+    * @param size     the new size required, see #getAllowedArguments for valid values
+    */
+   Archive resize(String username, int size);
+
+   /**
+    * Change the password for an archive user.
+    *
+    * @param username the archive username
+    * @param password the new password
+    */
+   Archive changePassword(String username, String password);
+
+   /**
+    * Lists the allowed arguments for some of the functions in this module such as archive size.
+    */
+   ArchiveAllowedArguments getAllowedArguments();
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncApi.java
new file mode 100644
index 0000000..4210f17
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/ArchiveAsyncApi.java
@@ -0,0 +1,115 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.Archive;
+import org.jclouds.glesys.domain.ArchiveAllowedArguments;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Archive data via the Glesys REST API.
+ * <p/>
+ *
+ * @author Adam Lowe
+ * @see ArchiveApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@RequestFilters(BasicAuthentication.class)
+public interface ArchiveAsyncApi {
+
+   /**
+    * @see ArchiveApi#list
+    */
+   @POST
+   @Path("/archive/list/format/json")
+   @SelectJson("archives")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<FluentIterable<Archive>> list();
+
+   /**
+    * @see ArchiveApi#get
+    */
+   @POST
+   @Path("/archive/details/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<Archive> get(@FormParam("username") String username);
+
+   /**
+    * @see ArchiveApi#createWithCredentialsAndSize
+    */
+   @POST
+   @Path("/archive/create/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<Archive> createWithCredentialsAndSize(@FormParam("username") String username, @FormParam("password") String password,
+                                        @FormParam("size")int size);
+
+   /**
+    * @see ArchiveApi#delete
+    */
+   @POST
+   @Path("/archive/delete/format/json")
+   ListenableFuture<Void> delete(@FormParam("username") String username);
+
+   /**
+    * @see ArchiveApi#resize
+    */
+   @POST
+   @Path("/archive/resize/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<Archive> resize(@FormParam("username") String username, @FormParam("size") int size);
+   /**
+    * @see ArchiveApi#changePassword
+    */
+   @POST
+   @Path("/archive/changepassword/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<Archive> changePassword(@FormParam("username") String username, @FormParam("password") String password);
+
+   /**
+    * @see org.jclouds.glesys.features.ArchiveApi#getAllowedArguments
+    */
+   @GET
+   @Path("/archive/allowedarguments/format/json")
+   @SelectJson("argumentslist")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<ArchiveAllowedArguments> getAllowedArguments();
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/DomainApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/DomainApi.java
new file mode 100644
index 0000000..2b393a0
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/DomainApi.java
@@ -0,0 +1,116 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.glesys.domain.Domain;
+import org.jclouds.glesys.domain.DomainRecord;
+import org.jclouds.glesys.options.AddDomainOptions;
+import org.jclouds.glesys.options.AddRecordOptions;
+import org.jclouds.glesys.options.DomainOptions;
+import org.jclouds.glesys.options.UpdateRecordOptions;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * Provides synchronous access to Domain requests.
+ * <p/>
+ *
+ * @author Adam Lowe
+ * @see DomainAsyncApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface DomainApi {
+
+   /**
+    * Get a list of all domains for this account.
+    *
+    * @return an account's associated domain objects.
+    */
+   FluentIterable<Domain> list();
+
+   /**
+    * Get a specific domain.
+    *
+    * @return the requested domain object.
+    */
+   Domain get(String domain);
+
+   /**
+    * Add a domain to the Glesys dns-system
+    *
+    * @param domain  the name of the domain to add.
+    * @param options optional parameters
+    * @return information about the added domain
+    */
+   Domain create(String domain, AddDomainOptions... options);
+
+   /**
+    * Update a domain to the Glesys dns-system
+    *
+    * @param domain  the name of the domain to add.
+    * @param options optional parameters
+    * @return information about the modified domain
+    */
+   Domain update(String domain, DomainOptions options);
+
+   /**
+    * Remove a domain to the Glesys dns-system
+    *
+    * @param domain the name of the domain to remove
+    */
+   void delete(String domain);
+
+   /**
+    * Retrieve the DNS records for a given domain
+    *
+    * @param domain the name of the domain to retrieve records for
+    */
+   Set<DomainRecord> listRecords(String domain);
+
+   /**
+    * Add a DNS Record
+    *
+    * @param domain  the domain to add the record to
+    * @param options optional settings for the record
+    */
+   DomainRecord createRecord(String domain, String host, String type, String data, AddRecordOptions... options);
+
+   /**
+    * Modify a specific DNS Record
+    *
+    * @param recordId the id for the record to edit
+    * @param options  the settings to change
+    * @see #listRecords to retrieve the necessary ids
+    */
+   DomainRecord updateRecord(String recordId, UpdateRecordOptions options);
+
+   /**
+    * Delete a DNS record
+    *
+    * @param recordId the id for the record to delete
+    * @see #listRecords to retrieve the necessary ids
+    */
+   void deleteRecord(String recordId);
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncApi.java
new file mode 100644
index 0000000..ccf3f09
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/DomainAsyncApi.java
@@ -0,0 +1,138 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.Domain;
+import org.jclouds.glesys.domain.DomainRecord;
+import org.jclouds.glesys.options.AddDomainOptions;
+import org.jclouds.glesys.options.AddRecordOptions;
+import org.jclouds.glesys.options.DomainOptions;
+import org.jclouds.glesys.options.UpdateRecordOptions;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Domain (DNS) data via the Glesys REST API.
+ * <p/>
+ *
+ * @author Adam Lowe
+ * @see DomainApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@RequestFilters(BasicAuthentication.class)
+public interface DomainAsyncApi {
+
+   /**
+    * @see org.jclouds.glesys.features.DomainApi#list
+    */
+   @POST
+   @Path("/domain/list/format/json")
+   @SelectJson("domains")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<FluentIterable<Domain>> list();
+
+   /**
+    * @see org.jclouds.glesys.features.DomainApi#get
+    */
+   @POST
+   @Path("/domain/details/format/json")
+   @SelectJson("domain")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<Domain> get(@FormParam("domainname") String name);
+
+   /**
+    * @see DomainApi#create
+    */
+   @POST
+   @Path("/domain/add/format/json")
+   @SelectJson("domain")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<Domain> create(@FormParam("domainname") String name, AddDomainOptions... options);
+
+   /**
+    * @see DomainApi#update
+    */
+   @POST
+   @Path("/domain/edit/format/json")
+   @SelectJson("domain")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<Domain> update(@FormParam("domainname") String domain, DomainOptions options);
+
+
+   /**
+    * @see DomainApi#delete
+    */
+   @POST
+   @Path("/domain/delete/format/json")
+   ListenableFuture<Void> delete(@FormParam("domainname") String domain);
+
+   /**
+    * @see DomainApi#listRecords
+    */
+   @POST
+   @Path("/domain/listrecords/format/json")
+   @SelectJson("records")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<Set<DomainRecord>> listRecords(@FormParam("domainname") String domain);
+
+   /**
+    * @see DomainApi#createRecord
+    */
+   @POST
+   @Path("/domain/addrecord/format/json")
+   @SelectJson("record")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<DomainRecord> createRecord(@FormParam("domainname") String domain, @FormParam("host") String host,
+                                    @FormParam("type") String type, @FormParam("data") String data,
+                                    AddRecordOptions... options);
+
+   /**
+    * @see DomainApi#updateRecord
+    */
+   @POST
+   @Path("/domain/updaterecord/format/json")
+   @SelectJson("record")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<DomainRecord> updateRecord(@FormParam("recordid") String record_id, UpdateRecordOptions options);
+
+   /**
+    * @see DomainApi#deleteRecord
+    */
+   @POST
+   @Path("/domain/deleterecord/format/json")
+   ListenableFuture<Void> deleteRecord(@FormParam("recordid") String recordId);
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAccountApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAccountApi.java
new file mode 100644
index 0000000..e00725c
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAccountApi.java
@@ -0,0 +1,106 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.glesys.domain.EmailAccount;
+import org.jclouds.glesys.domain.EmailAlias;
+import org.jclouds.glesys.domain.EmailOverview;
+import org.jclouds.glesys.options.CreateAccountOptions;
+import org.jclouds.glesys.options.UpdateAccountOptions;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * Provides synchronous access to E-Mail requests.
+ * <p/>
+ *
+ * @author Adam Lowe
+ * @see org.jclouds.glesys.features.EmailAccountAsyncApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface EmailAccountApi {
+
+   /**
+    * Get a summary of e-mail accounts associated with this Glesys account
+    *
+    * @return the relevant summary data
+    */
+   EmailOverview getOverview();
+
+   /**
+    * Get the set of detailed information about e-mail accounts
+    *
+    * @return the relevant set of details
+    */
+   FluentIterable<EmailAccount> listDomain(String domain);
+
+   /**
+    * Get the set of details about e-mail aliases
+    *
+    * @return the relevant set of details
+    */
+   FluentIterable<EmailAlias> listAliasesInDomain(String domain);
+
+   /**
+    * Create a new e-mail account
+    *
+    * @param accountAddress the e-mail address to use (the domain should already exist)
+    * @param password       the password to use for the mailbox
+    * @param options        optional parameters
+    * @see DomainApi#create
+    */
+   EmailAccount createWithPassword(String accountAddress, String password, CreateAccountOptions... options);
+
+   /**
+    * Create an e-mail alias for an e-mail account
+    *
+    * @param aliasAddress   the address to use for the alias  (the domain should already exist)
+    * @param toEmailAddress the existing e-mail account address the alias should forward to
+    * @see DomainApi#create
+    */
+   EmailAlias createAlias(String aliasAddress, String toEmailAddress);
+
+   /**
+    * Adjust an e-mail account's settings
+    *
+    * @param accountAddress the existing e-mail account address
+    * @param options        optional parameters
+    */
+   EmailAccount update(String accountAddress, UpdateAccountOptions... options);
+
+   /**
+    * Adjust (re-target) an e-mail alias
+    *
+    * @param aliasAddress   the existing alias e-mail address
+    * @param toEmailAddress the existing e-mail account address the alias should forward to
+    */
+   EmailAlias updateAlias(String aliasAddress, String toEmailAddress);
+
+   /**
+    * Delete an e-mail account or alias
+    *
+    * @param accountAddress the existing alias e-mail account or alias address
+    */
+   boolean delete(String accountAddress);
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAccountAsyncApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAccountAsyncApi.java
new file mode 100644
index 0000000..aaedf50
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/EmailAccountAsyncApi.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.EmailAccount;
+import org.jclouds.glesys.domain.EmailAlias;
+import org.jclouds.glesys.domain.EmailOverview;
+import org.jclouds.glesys.options.CreateAccountOptions;
+import org.jclouds.glesys.options.UpdateAccountOptions;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.http.functions.ReturnTrueOn404;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to E-Mail data via the Glesys REST API.
+ * <p/>
+ *
+ * @author Adam Lowe
+ * @see org.jclouds.glesys.features.EmailAccountApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@RequestFilters(BasicAuthentication.class)
+public interface EmailAccountAsyncApi {
+
+   /**
+    * @see org.jclouds.glesys.features.EmailAccountApi#getOverview
+    */
+   @POST
+   @Path("/email/overview/format/json")
+   @SelectJson("overview")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<EmailOverview> getOverview();
+
+   /**
+    * @see org.jclouds.glesys.features.EmailAccountApi#listDomain
+    */
+   @POST
+   @Path("/email/list/format/json")
+   @SelectJson("emailaccounts")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<FluentIterable<EmailAccount>> listDomain(@FormParam("domainname") String domain);
+
+   /**
+    * @see org.jclouds.glesys.features.EmailAccountApi#listAliasesInDomain
+    */
+   @POST
+   @Path("/email/list/format/json")
+   @SelectJson("emailaliases")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<FluentIterable<EmailAlias>> listAliasesInDomain(@FormParam("domainname") String domain);
+
+   /**
+    * @see org.jclouds.glesys.features.EmailAccountApi#createWithPassword
+    */
+   @POST
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("emailaccount")
+   @Path("/email/createaccount/format/json")
+   ListenableFuture<EmailAccount> createWithPassword(@FormParam("emailaccount") String accountAddress, @FormParam("password") String password, CreateAccountOptions... options);
+
+   /**
+    * @see org.jclouds.glesys.features.EmailAccountApi#createAlias
+    */
+   @POST
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("alias")
+   @Path("/email/createalias/format/json")
+   ListenableFuture<EmailAlias> createAlias(@FormParam("emailalias") String aliasAddress, @FormParam("goto") String toEmailAddress);
+
+   /**
+    * @see org.jclouds.glesys.features.EmailAccountApi#update
+    */
+   @POST
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("emailaccount")
+   @Path("/email/editaccount/format/json")
+   ListenableFuture<EmailAccount> update(@FormParam("emailaccount") String accountAddress, UpdateAccountOptions... options);
+
+   /**
+    * @see org.jclouds.glesys.features.EmailAccountApi#updateAlias
+    */
+   @POST
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("alias")
+   @Path("/email/editalias/format/json")
+   ListenableFuture<EmailAlias> updateAlias(@FormParam("emailalias") String aliasAddress, @FormParam("goto") String toEmailAddress);
+
+   /**
+    * @see org.jclouds.glesys.features.EmailAccountApi#delete
+    */
+   @POST
+   @Path("/email/delete/format/json")
+   @ExceptionParser(ReturnTrueOn404.class)
+   ListenableFuture<Boolean> delete(@FormParam("email") String accountAddress);
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/IpApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/IpApi.java
new file mode 100644
index 0000000..571be6b
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/IpApi.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.glesys.domain.IpDetails;
+import org.jclouds.glesys.options.ListIpOptions;
+
+import com.google.common.collect.FluentIterable;
+
+/**
+ * Provides synchronous access to IP Addresses.
+ * <p/>
+ *
+ * @author Adrian Cole, Mattias Holmqvist, Adam Lowe
+ * @see IpAsyncApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface IpApi {
+   /**
+    * Get a set of all IP addresses that are available and not used on any account or server.
+    *
+    * @param ipVersion  4 or 6, for IPV4 or IPV6, respectively
+    * @param datacenter the datacenter
+    * @param platform   the platform
+    * @return a set of free IP addresses
+    */
+   FluentIterable<String> listFree(int ipVersion, String datacenter, String platform);
+
+   /**
+    * Take a free IP address and add it to this account. You can list free IP addresses with the function listFree().
+    * Once your free IP on this account you can add it to a server with the add() function.
+    *
+    * @param ipAddress the IP address to be add to this account (reserve)
+    */
+   IpDetails take(String ipAddress);
+
+   /**
+    * Return an unused IP address to the pool of free ips. If the IP address is allocated to a server,
+    * it must first be removed by calling remove(ipAddress) before it can be released.
+    *
+    * @param ipAddress the IP address to be released
+    */
+   IpDetails release(String ipAddress);
+
+   /**
+    * Get IP addresses associated with your account (reserved, assigned to servers, etc)
+    *
+    * @param options options to filter the results (by IPV4/6, serverId, etc)
+    * @return the set of IP addresses
+    */
+   FluentIterable<IpDetails> list(ListIpOptions... options);
+
+   /**
+    * Get details about the given IP address such as gateway and netmask. Different details are available
+    * on different platforms.
+    *
+    * @param ipAddress the ip address
+    * @return details about the given IP address
+    */
+   IpDetails get(String ipAddress);
+
+   /**
+    * Add an IP address to an server. The IP has to be free, but reserved to this account. You are able to list such addresses
+    * with listOwn() and reserve an address for this account by using take(). To find free ips you can use ip/listfree
+    * ip to an Xen-server you have to configure the server yourself, unless the ip was added during the c
+    * server (server/create). You can get detailed information such as gateway and netmask using the ip
+    *
+    * @param ipAddress the IP address to remove
+    * @param serverId  the server to add the IP address to
+    */
+   IpDetails addToServer(String ipAddress, String serverId);
+
+   /**
+    * Remove an IP address from a server. This does not release it back to GleSYS pool of free ips. The address will be
+    * kept on the account so that you can use it for other servers or the same server at a later time. To completely remove
+    * the IP address from this account, use removeFromServerAndRelease to do so
+    *
+    * @param ipAddress the IP address to remove
+    * @param serverId  the server to remove the IP address from
+    * @see #removeFromServerAndRelease
+    */
+   IpDetails removeFromServer(String ipAddress, String serverId);
+
+   /**
+    * Remove an IP address from a server and release it back to GleSYS pool of free ips.
+    *
+    * @param ipAddress the IP address to remove
+    * @param serverId  the server to remove the IP address from
+    * @see #removeFromServer
+    */
+   IpDetails removeFromServerAndRelease(String ipAddress, String serverId);
+
+   /**
+    * Sets PTR data for an IP. Use ip/listown or ip/details to get current PTR data
+    */
+   IpDetails setPtr(String ipAddress, String ptr);
+
+   /**
+    * Resets PTR data for an IP back to the default value
+    */
+   IpDetails resetPtr(String ipAddress);
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncApi.java
new file mode 100644
index 0000000..3695f0d
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/IpAsyncApi.java
@@ -0,0 +1,153 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.IpDetails;
+import org.jclouds.glesys.options.ListIpOptions;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to IP Addresses via their REST API.
+ * <p/>
+ *
+ * @author Adrian Cole, Mattias Holmqvist, Adam Lowe
+ * @see IpApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@RequestFilters(BasicAuthentication.class)
+public interface IpAsyncApi {
+   /**
+    * @see IpApi#listFree
+    */
+   @GET
+   @Path("/ip/listfree/ipversion/{ipversion}/datacenter/{datacenter}/platform/{platform}/format/json")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("ipaddresses")
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<FluentIterable<String>> listFree(@PathParam("ipversion") int ipversion,
+                                          @PathParam("datacenter") String datacenter,
+                                          @PathParam("platform") String platform);
+
+   /**
+    * @see IpApi#take
+    */
+   @POST
+   @Path("/ip/take/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<IpDetails> take(@FormParam("ipaddress") String ipAddress);
+
+   /**
+    * @see IpApi#release
+    */
+   @POST
+   @Path("/ip/release/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<IpDetails> release(@FormParam("ipaddress") String ipAddress);
+
+   /**
+    * @see IpApi#list
+    */
+   @GET
+   @Path("/ip/listown/format/json")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @SelectJson("iplist")
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<FluentIterable<IpDetails>> list(ListIpOptions... options);
+
+   /**
+    * @see IpApi#get
+    */
+   @GET
+   @Path("/ip/details/ipaddress/{ipaddress}/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<IpDetails> get(@PathParam("ipaddress") String ipAddress);
+
+   /**
+    * @see IpApi#addToServer
+    */
+   @POST
+   @Path("/ip/add/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<IpDetails> addToServer(@FormParam("ipaddress") String ipAddress,
+                                             @FormParam("serverid") String serverId);
+
+   /**
+    * @see IpApi#removeFromServer
+    */
+   @POST
+   @Path("/ip/remove/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<IpDetails> removeFromServer(@FormParam("ipaddress") String ipAddress,
+                                                  @FormParam("serverid") String serverId);
+
+   /**
+    * @see IpApi#removeFromServer
+    */
+   @POST
+   @FormParams(keys = "release", values = "true")
+   @Path("/ip/remove/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<IpDetails> removeFromServerAndRelease(@FormParam("ipaddress") String ipAddress,
+                                                            @FormParam("serverid") String serverId);
+
+   /**
+    * @see IpApi#setPtr
+    */
+   @POST
+   @Path("/ip/setptr/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<IpDetails> setPtr(@FormParam("ipaddress") String ipAddress,
+                                      @FormParam("data") String ptr);
+
+   /**
+    * @see IpApi#resetPtr
+    */
+   @POST
+   @Path("/ip/resetptr/format/json")
+   @SelectJson("details")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<IpDetails> resetPtr(@FormParam("ipaddress") String ipAddress);
+
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/ServerApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/ServerApi.java
new file mode 100644
index 0000000..da32f36
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/ServerApi.java
@@ -0,0 +1,205 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
+import org.jclouds.glesys.domain.Console;
+import org.jclouds.glesys.domain.OSTemplate;
+import org.jclouds.glesys.domain.ResourceUsage;
+import org.jclouds.glesys.domain.Server;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.glesys.domain.ServerLimit;
+import org.jclouds.glesys.domain.ServerSpec;
+import org.jclouds.glesys.domain.ServerStatus;
+import org.jclouds.glesys.options.CloneServerOptions;
+import org.jclouds.glesys.options.CreateServerOptions;
+import org.jclouds.glesys.options.DestroyServerOptions;
+import org.jclouds.glesys.options.UpdateServerOptions;
+import org.jclouds.glesys.options.ServerStatusOptions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+
+/**
+ * Provides synchronous access to Server.
+ * <p/>
+ *
+ * @author Adrian Cole
+ * @author Adam Lowe
+ * @see ServerAsyncApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
+public interface ServerApi {
+
+   /**
+    * Get a list of all servers on this account.
+    *
+    * @return an account's associated server objects.
+    */
+   FluentIterable<Server> list();
+
+   /**
+    * Get detailed information about a server such as hostname, hardware
+    * configuration (cpu, memory and disk), ip addresses, cost, transfer, os and
+    * more.
+    *
+    * @param id id of the server
+    * @return server or null if not found
+    */
+   ServerDetails get(String id);
+
+   /**
+    * Get detailed information about a server status including up-time and
+    * hardware usage (cpu, disk, memory and bandwidth)
+    *
+    * @param id      id of the server
+    * @param options optional parameters
+    * @return the status of the server or null if not found
+    */
+   ServerStatus getStatus(String id, ServerStatusOptions... options);
+
+   /**
+    * Get detailed information about a server's limits (for OpenVZ only).
+    * <p/>
+    *
+    * @param id id of the server
+    * @return the requested information about the server or null if not found
+    */
+   Map<String, ServerLimit> getLimits(String id);
+
+   /**
+    * Get information about how to connect to a server via VNC
+    *
+    * @param id id of the server
+    * @return the requested information about the server or null if not found
+    */
+   Console getConsole(String id);
+
+   /**
+    * Get information about the OS templates available
+    *
+    * @return the set of information about each template
+    */
+   FluentIterable<OSTemplate> listTemplates();
+
+   /**
+    * Get information about valid arguments to #createServer for each platform
+    *
+    * @return a map of argument lists, keyed on platform
+    */
+   Map<String, AllowedArgumentsForCreateServer> getAllowedArgumentsForCreateByPlatform();
+
+   /**
+    * Reset the fail count for a server limit (for OpenVZ only).
+    *
+    * @param id   id of the server
+    * @param type the type of limit to reset
+    */
+   Map<String, ServerLimit> resetLimit(String id, String type);
+
+   /**
+    * Reboot a server
+    *
+    * @param id id of the server
+    */
+   ServerDetails reboot(String id);
+
+   /**
+    * Start a server
+    *
+    * @param id id of the server
+    */
+   ServerDetails start(String id);
+
+   /**
+    * Stop a server
+    *
+    * @param id id of the server
+    */
+   ServerDetails stop(String id);
+
+   /**
+    * hard stop a server
+    *
+    * @param id id of the server
+    */
+   ServerDetails hardStop(String id);
+
+   /**
+    * Create a new server
+    *
+    * @param hostname     the host name of the new server
+    * @param rootPassword the root password to use
+    * @param options      optional settings ex. description
+    */
+   @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
+   ServerDetails createWithHostnameAndRootPassword(ServerSpec serverSpec, String hostname, String rootPassword,
+         CreateServerOptions... options);
+
+   /**
+    * Update the configuration of a server
+    *
+    * @param serverid the serverId of the server to edit
+    * @param options  the settings to change
+    */
+   ServerDetails update(String serverid, UpdateServerOptions options);
+
+   /**
+    * Clone a server
+    *
+    * @param serverid the serverId of the server to clone
+    * @param hostname the new host name of the cloned server
+    * @param options  the settings to change
+    */
+   @Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
+   ServerDetails clone(String serverid, String hostname, CloneServerOptions... options);
+
+   /**
+    * Destroy a server
+    *
+    * @param id     the id of the server
+    * @param keepIp if DestroyServerOptions.keepIp(true) the servers ip will be retained for use in your GleSYS account
+    */
+   ServerDetails destroy(String id, DestroyServerOptions keepIp);
+
+   /**
+    * Reset the root password of a server
+    *
+    * @param id       the id of the server
+    * @param password the new password to use
+    */
+   ServerDetails resetPassword(String id, String password);
+
+   /**
+    * Return resource usage over time for server
+    *
+    * @param id       the id of the server
+    * @param resource the name of the resource to retrieve usage information for (e.g. "cpuusage")
+    * @param resolution the time-period to extract data for (one of "minute", "hour" or "day)
+    */
+   @Beta
+   // TODO: better name
+   ResourceUsage getResourceUsage(String id, String resource, String resolution);
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncApi.java b/providers/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncApi.java
new file mode 100644
index 0000000..8024622
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/features/ServerAsyncApi.java
@@ -0,0 +1,245 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import java.util.Map;
+import java.util.SortedMap;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
+import org.jclouds.glesys.domain.Console;
+import org.jclouds.glesys.domain.OSTemplate;
+import org.jclouds.glesys.domain.ResourceUsage;
+import org.jclouds.glesys.domain.Server;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.glesys.domain.ServerLimit;
+import org.jclouds.glesys.domain.ServerSpec;
+import org.jclouds.glesys.domain.ServerStatus;
+import org.jclouds.glesys.functions.ParseTemplatesFromHttpResponse;
+import org.jclouds.glesys.options.CloneServerOptions;
+import org.jclouds.glesys.options.CreateServerOptions;
+import org.jclouds.glesys.options.DestroyServerOptions;
+import org.jclouds.glesys.options.UpdateServerOptions;
+import org.jclouds.glesys.options.ServerStatusOptions;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.FormParams;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SelectJson;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to Server via their REST API.
+ * <p/>
+ * 
+ * @author Adrian Cole
+ * @author Adam Lowe
+ * @see ServerApi
+ * @see <a href="https://customer.glesys.com/api.php" />
+ */
+@RequestFilters(BasicAuthentication.class)
+public interface ServerAsyncApi {
+
+   /**
+    * @see ServerApi#list
+    */
+   @POST
+   @Path("/server/list/format/json")
+   @SelectJson("servers")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   ListenableFuture<FluentIterable<Server>> list();
+
+   /**
+    * @see ServerApi#get
+    */
+   @POST
+   @Path("/server/details/format/json")
+   @SelectJson("server")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @FormParams(keys = "includestate", values = "true")
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<ServerDetails> get(@FormParam("serverid") String id);
+
+   /**
+    * @see ServerApi#getStatus
+    */
+   @POST
+   @Path("/server/status/format/json")
+   @SelectJson("server")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<ServerStatus> getStatus(@FormParam("serverid") String id, ServerStatusOptions... options);
+
+   /**
+    * @see ServerApi#getLimits
+    */
+   @POST
+   @Path("/server/limits/format/json")
+   @SelectJson("limits")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<SortedMap<String, ServerLimit>> getLimits(@FormParam("serverid") String id);
+
+   /**
+    * @see ServerApi#getConsole
+    */
+   @POST
+   @Path("/server/console/format/json")
+   @SelectJson("console")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+   ListenableFuture<Console> getConsole(@FormParam("serverid") String id);
+
+   /**
+    * @see ServerApi#getAllowedArgumentsForCreateByPlatform
+    */
+   @GET
+   @Path("/server/allowedarguments/format/json")
+   @SelectJson("argumentslist")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<Map<String, AllowedArgumentsForCreateServer>> getAllowedArgumentsForCreateByPlatform();
+
+   /**
+    * @see ServerApi#listTemplates
+    */
+   @GET
+   @Path("/server/templates/format/json")
+   @ResponseParser(ParseTemplatesFromHttpResponse.class)
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<FluentIterable<OSTemplate>> listTemplates();
+
+   /**
+    * @see ServerApi#stop
+    */
+   @POST
+   @Path("/server/resetlimit/format/json")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<SortedMap<String, ServerLimit>> resetLimit(@FormParam("serverid") String id,
+         @FormParam("type") String type);
+
+   /**
+    * @see ServerApi#reboot
+    */
+   @POST
+   @SelectJson("server")
+   @Path("/server/reboot/format/json")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<ServerDetails> reboot(@FormParam("serverid") String id);
+
+   /**
+    * @see ServerApi#start
+    */
+   @POST
+   @SelectJson("server")
+   @Path("/server/start/format/json")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<ServerDetails> start(@FormParam("serverid") String id);
+
+   /**
+    * @see ServerApi#stop
+    */
+   @POST
+   @SelectJson("server")
+   @Path("/server/stop/format/json")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<ServerDetails> stop(@FormParam("serverid") String id);
+
+   /**
+    * @see ServerApi#hardStop
+    */
+   @POST
+   @SelectJson("server")
+   @Path("/server/stop/format/json")
+   @FormParams(keys = "type", values = "hard")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<ServerDetails> hardStop(@FormParam("serverid") String id);
+
+   /**
+    * @see ServerApi#createWithHostnameAndRootPassword
+    */
+   @POST
+   @SelectJson("server")
+   @Path("/server/create/format/json")
+   @Consumes(MediaType.APPLICATION_JSON)
+   @MapBinder(CreateServerOptions.class)
+   ListenableFuture<ServerDetails> createWithHostnameAndRootPassword(ServerSpec serverSpec,
+         @PayloadParam("hostname") String hostname, @PayloadParam("rootpassword") String rootPassword,
+         CreateServerOptions... options);
+
+   /**
+    * @see ServerApi#clone
+    */
+   @POST
+   @Path("/server/clone/format/json")
+   @SelectJson("server")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<ServerDetails> clone(@FormParam("serverid") String serverid,
+         @FormParam("hostname") String hostname, CloneServerOptions... options);
+
+   /**
+    * @see ServerApi#update
+    */
+   @POST
+   @Path("/server/edit/format/json")
+   @SelectJson("server")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<ServerDetails> update(@FormParam("serverid") String serverid, UpdateServerOptions options);
+
+   /**
+    * @see ServerApi#destroy
+    */
+   @POST
+   @Path("/server/destroy/format/json")
+   ListenableFuture<Void> destroy(@FormParam("serverid") String id, DestroyServerOptions keepIp);
+
+   /**
+    * @see ServerApi#resetPassword
+    */
+   @POST
+   @Path("/server/resetpassword/format/json")
+   @SelectJson("server")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<ServerDetails> resetPassword(@FormParam("serverid") String id, @FormParam("rootpassword") String password);
+
+   /**
+    * @see ServerApi#getResourceUsage
+    */
+   @POST
+   @Path("/server/resourceusage/format/json")
+   @SelectJson("usage")
+   @Consumes(MediaType.APPLICATION_JSON)
+   ListenableFuture<ResourceUsage> getResourceUsage(@FormParam("serverid") String id, @FormParam("resource") String resource,
+         @FormParam("resolution") String resolution);
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java b/providers/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java
new file mode 100644
index 0000000..60738f3
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/functions/ParseTemplatesFromHttpResponse.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Singleton;
+
+import org.jclouds.glesys.domain.OSTemplate;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.functions.ParseFirstJsonValueNamed;
+import org.jclouds.json.internal.GsonWrapper;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
+/**
+ * @author Adrian Cole
+ */
+@Singleton
+public class ParseTemplatesFromHttpResponse implements Function<HttpResponse, FluentIterable<OSTemplate>> {
+   private final ParseFirstJsonValueNamed<Map<String, Set<OSTemplate>>> parser;
+
+   @Inject
+   public ParseTemplatesFromHttpResponse(GsonWrapper gsonView) {
+      this.parser = new ParseFirstJsonValueNamed<Map<String, Set<OSTemplate>>>(checkNotNull(gsonView,
+               "gsonView"), new TypeLiteral<Map<String, Set<OSTemplate>>>() {
+      }, "templates");
+   }
+
+   public FluentIterable<OSTemplate> apply(HttpResponse response) {
+      checkNotNull(response, "response");
+      Map<String, Set<OSTemplate>> toParse = parser.apply(response);
+      checkNotNull(toParse, "parsed result from %s", response);
+      return FluentIterable.from(Iterables.concat(toParse.values()));
+   }
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java b/providers/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java
new file mode 100644
index 0000000..8391069
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/functions/internal/GleSYSTypeAdapters.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.functions.internal;
+
+import java.io.IOException;
+
+import org.jclouds.glesys.domain.GleSYSBoolean;
+import org.jclouds.glesys.domain.Server;
+
+import com.google.common.base.Objects;
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+
+/**
+ * @author Adam Lowe
+ */
+public class GleSYSTypeAdapters {
+
+   public static class ServerStateAdapter extends TypeAdapter<Server.State> {
+      @Override
+      public void write(JsonWriter writer, Server.State value) throws IOException {
+         writer.value(value.value());
+      }
+
+      @Override
+      public Server.State read(JsonReader reader) throws IOException {
+         if (reader.peek() == JsonToken.NULL) {
+            reader.nextNull();
+            return Server.State.UNRECOGNIZED;
+         }
+         return Server.State.fromValue(reader.nextString());
+      }
+   }
+
+   public static class GleSYSBooleanAdapter extends TypeAdapter<GleSYSBoolean> {
+
+      @Override
+      public void write(JsonWriter writer, GleSYSBoolean value) throws IOException {
+         writer.value(value.getValue() ? "yes" : "no");
+      }
+
+      @Override
+      public GleSYSBoolean read(JsonReader in) throws IOException {
+         if (in.peek() == JsonToken.BOOLEAN) {
+            return new GleSYSBoolean(in.nextBoolean());
+         } else if (in.peek() == JsonToken.NULL) {
+            return GleSYSBoolean.FALSE;
+         } else {
+            return new GleSYSBoolean(Objects.equal(in.nextString(), "yes"));
+         }
+      }
+
+   }
+
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java b/providers/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java
new file mode 100644
index 0000000..f6fd125
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/handlers/GleSYSErrorHandler.java
@@ -0,0 +1,98 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.handlers;
+
+import java.io.IOException;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.jclouds.util.Strings2;
+
+import com.google.common.base.Throwables;
+import com.google.common.io.Closeables;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ * 
+ * @author Adrian Cole
+ * 
+ */
+@Singleton
+public class GleSYSErrorHandler implements HttpErrorHandler {
+
+   public void handleError(HttpCommand command, HttpResponse response) {
+      // it is important to always read fully and close streams
+      String message = parseMessage(response);
+      Exception exception = message != null ? new HttpResponseException(command, response, message)
+            : new HttpResponseException(command, response);
+      try {
+         message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+               response.getStatusLine());
+         switch (response.getStatusCode()) {
+         case 401:
+         case 403:
+            exception = new AuthorizationException(message, exception);
+            break;
+         case 400:
+            if (message.indexOf("not find") != -1) {
+               exception = new ResourceNotFoundException(message, exception);
+            }
+            break;
+         case 404:
+            if (message.indexOf("Not supported") != -1) {
+               exception = new UnsupportedOperationException(message, exception);
+            } else {
+               exception = new ResourceNotFoundException(message, exception);
+            }
+            break;
+         case 500:
+            if (message.indexOf("Locked") != -1) {
+               exception = new IllegalStateException(message, exception);
+            }
+            break;
+         }
+      } finally {
+         if (response.getPayload() != null)
+            Closeables.closeQuietly(response.getPayload().getInput());
+         command.setException(exception);
+      }
+   }
+
+   public String parseMessage(HttpResponse response) {
+      if (response.getPayload() == null)
+         return null;
+      try {
+         return Strings2.toString(response.getPayload());
+      } catch (IOException e) {
+         throw new RuntimeException(e);
+      } finally {
+         try {
+            response.getPayload().getInput().close();
+         } catch (IOException e) {
+            Throwables.propagate(e);
+         }
+      }
+   }
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/AddDomainOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/AddDomainOptions.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/options/AddDomainOptions.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/options/AddDomainOptions.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/AddRecordOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/AddRecordOptions.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/options/AddRecordOptions.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/options/AddRecordOptions.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java
new file mode 100644
index 0000000..4185c08
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/options/CloneServerOptions.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.options;
+
+/**
+ * @author Adam Lowe
+ */
+public class CloneServerOptions extends UpdateServerOptions {
+   public static class Builder {
+      /**
+       * @see org.jclouds.glesys.options.CloneServerOptions#diskSizeGB
+       */
+      public static CloneServerOptions diskSizeGB(int diskSizeGB) {
+         return CloneServerOptions.class.cast(new CloneServerOptions().diskSizeGB(diskSizeGB));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.CloneServerOptions#memorySizeMB
+       */
+      public static CloneServerOptions memorySizeMB(int memorySizeMB) {
+         return CloneServerOptions.class.cast(new CloneServerOptions().memorySizeMB(memorySizeMB));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.CloneServerOptions#cpuCores
+       */
+      public static CloneServerOptions cpucores(int cpucores) {
+         return CloneServerOptions.class.cast(new CloneServerOptions().cpuCores(cpucores));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.CloneServerOptions#transferGB
+       */
+      public static CloneServerOptions transferGB(int transferGB) {
+         return CloneServerOptions.class.cast(new CloneServerOptions().transferGB(transferGB));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateServerOptions#description
+       */
+      public static CloneServerOptions description(String description) {
+         return CloneServerOptions.class.cast(new CloneServerOptions().description(description));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.CloneServerOptions#dataCenter
+       */
+      public static CloneServerOptions dataCenter(String dataCenter) {
+         return new CloneServerOptions().dataCenter(dataCenter);
+      }
+   }
+
+   /**
+    * Configure which datacenter to create the clone in
+    */
+   public CloneServerOptions dataCenter(String dataCenter) {
+      formParameters.put("datacenter", dataCenter);
+      return this;
+   }
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/CreateAccountOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/CreateAccountOptions.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/options/CreateAccountOptions.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/options/CreateAccountOptions.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/options/CreateServerOptions.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/DestroyServerOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/DestroyServerOptions.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/options/DestroyServerOptions.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/options/DestroyServerOptions.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/options/DomainOptions.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/ListIpOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/ListIpOptions.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/options/ListIpOptions.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/options/ListIpOptions.java
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/options/ServerStatusOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/ServerStatusOptions.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/options/ServerStatusOptions.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/options/ServerStatusOptions.java
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateAccountOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateAccountOptions.java
new file mode 100644
index 0000000..9c3c5a3
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateAccountOptions.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.options;
+
+
+/**
+ * @author Adam Lowe
+ * @see <a href="https://customer.glesys.com/api.php?a=doc#email_editaccount" />
+ */
+public class UpdateAccountOptions extends CreateAccountOptions {
+
+   public static class Builder {
+      /**
+       * @see org.jclouds.glesys.options.UpdateAccountOptions#antispamLevel
+       */
+      public static UpdateAccountOptions antispamLevel(int antispamLevel) {
+         return UpdateAccountOptions.class.cast(new UpdateAccountOptions().antispamLevel(antispamLevel));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateAccountOptions#antiVirus
+       */
+      public static UpdateAccountOptions antiVirus(boolean antiVirus) {
+         return UpdateAccountOptions.class.cast(new UpdateAccountOptions().antiVirus(antiVirus));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateAccountOptions#autorespond
+       */
+      public static UpdateAccountOptions autorespond(boolean autorespond) {
+         return UpdateAccountOptions.class.cast(new UpdateAccountOptions().autorespond(autorespond));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateAccountOptions#autorespondSaveEmail
+       */
+      public static UpdateAccountOptions autorespondSaveEmail(boolean autorespondSaveEmail) {
+         return UpdateAccountOptions.class.cast(new UpdateAccountOptions().autorespondSaveEmail(autorespondSaveEmail));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateAccountOptions#autorespondMessage
+       */
+      public static UpdateAccountOptions autorespondMessage(String autorespondMessage) {
+         return UpdateAccountOptions.class.cast(new UpdateAccountOptions().autorespondMessage(autorespondMessage));
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateAccountOptions#password
+       */
+      public static UpdateAccountOptions password(String password) {
+         return new UpdateAccountOptions().password(password);
+      }
+   }
+
+   /** Reset the password for this account */
+   public UpdateAccountOptions password(String password) {
+      formParameters.put("password", password);
+      return this;
+   }
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateRecordOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateRecordOptions.java
new file mode 100644
index 0000000..8fa7571
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateRecordOptions.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.options;
+
+/**
+ * @author Adam Lowe
+ */
+public class UpdateRecordOptions extends AddRecordOptions {
+
+   public static class Builder {
+      /**
+       * @see UpdateRecordOptions#host
+       */
+      public static UpdateRecordOptions host(String host) {
+         return new UpdateRecordOptions().host(host);
+      }
+
+      /**
+       * @see UpdateRecordOptions#type
+       */
+      public static UpdateRecordOptions type(String type) {
+         return new UpdateRecordOptions().type(type);
+      }
+
+      /**
+       * @see UpdateRecordOptions#data
+       */
+      public static UpdateRecordOptions data(String data) {
+         return new UpdateRecordOptions().data(data);
+      }
+
+      /**
+       * @see UpdateRecordOptions#ttl
+       */
+      public static UpdateRecordOptions ttl(int ttl) {
+         return UpdateRecordOptions.class.cast(new UpdateRecordOptions().ttl(ttl));
+      }
+   }
+
+
+   /** Configure the hostname attached to this record */
+   public UpdateRecordOptions host(String host) {
+      formParameters.put("host", host);
+      return this;
+   }
+
+   /** Configure the type of record, ex. "A", "CNAME" or "MX"  */
+   public UpdateRecordOptions type(String type) {
+      formParameters.put("type", type);
+      return this;
+   }
+
+   /** Set the content of this record (depending on type, for an "A" record this would be an ip address) */
+   public UpdateRecordOptions data(String data) {
+      formParameters.put("data", data);
+      return this;
+   }
+
+   @Override
+   public UpdateRecordOptions ttl(int ttl) {
+      return UpdateRecordOptions.class.cast(super.ttl(ttl));
+   }
+}
diff --git a/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateServerOptions.java b/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateServerOptions.java
new file mode 100644
index 0000000..c17516a
--- /dev/null
+++ b/providers/glesys/src/main/java/org/jclouds/glesys/options/UpdateServerOptions.java
@@ -0,0 +1,112 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.options;
+
+import org.jclouds.http.options.BaseHttpRequestOptions;
+
+/**
+ * 
+ * @author Adam Lowe
+ */
+public class UpdateServerOptions extends BaseHttpRequestOptions {
+
+   public static class Builder {
+      /**
+       * @see org.jclouds.glesys.options.UpdateServerOptions#diskSizeGB
+       */
+      public static UpdateServerOptions disksizeGB(int disksizeGB) {
+         return new UpdateServerOptions().diskSizeGB(disksizeGB);
+      }
+      
+      /**
+       * @see org.jclouds.glesys.options.UpdateServerOptions#memorySizeMB
+       */
+      public static UpdateServerOptions memorysizeMB(int memorysizeMB) {
+         return new UpdateServerOptions().memorySizeMB(memorysizeMB);
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateServerOptions#cpuCores
+       */
+      public static UpdateServerOptions cpucores(int cpucores) {
+         UpdateServerOptions options = new UpdateServerOptions();
+         return options.cpuCores(cpucores);
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateServerOptions#transferGB
+       */
+      public static UpdateServerOptions transferGB(int transferGB) {
+         return new UpdateServerOptions().transferGB(transferGB);
+      }
+      
+      /**
+       * @see org.jclouds.glesys.options.UpdateServerOptions#hostname
+       */
+      public static UpdateServerOptions hostname(String hostname) {
+         UpdateServerOptions options = new UpdateServerOptions();
+         return options.hostname(hostname);
+      }
+
+      /**
+       * @see org.jclouds.glesys.options.UpdateServerOptions#description
+       */
+      public static UpdateServerOptions description(String description) {
+         UpdateServerOptions options = new UpdateServerOptions();
+         return options.description(description);
+      }
+   }
+
+   /** Configure the size of the disk, in GB, of the server */
+   public UpdateServerOptions diskSizeGB(int diskSizeGB) {
+      formParameters.put("disksize", Integer.toString(diskSizeGB));
+      return this;
+   }
+
+   /** Configure the amount of RAM, in MB, allocated to the server */
+   public UpdateServerOptions memorySizeMB(int memorySizeMB) {
+      formParameters.put("memorysize", Integer.toString(memorySizeMB));
+      return this;
+   }
+
+   /** Configure the number of CPU cores allocated to the server */
+   public UpdateServerOptions cpuCores(int cpucores) {
+      formParameters.put("cpucores", Integer.toString(cpucores));
+      return this;
+   }
+
+   /** Configure the transfer setting for the server */
+   public UpdateServerOptions transferGB(int transferGB) {
+      formParameters.put("transfer", Integer.toString(transferGB));
+      return this;
+   }
+
+   /** Configure the host name of the server (must be unique within the GleSYS account) */
+   public UpdateServerOptions hostname(String hostname) {
+      formParameters.put("hostname", hostname);
+      return this;
+   }
+
+   /** Configure the description of the server */
+   public UpdateServerOptions description(String description) {
+      formParameters.put("description", description);
+      return this;
+   }
+
+}
diff --git a/labs/glesys/src/main/java/org/jclouds/glesys/reference/GleSYSConstants.java b/providers/glesys/src/main/java/org/jclouds/glesys/reference/GleSYSConstants.java
similarity index 100%
rename from labs/glesys/src/main/java/org/jclouds/glesys/reference/GleSYSConstants.java
rename to providers/glesys/src/main/java/org/jclouds/glesys/reference/GleSYSConstants.java
diff --git a/labs/glesys/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata b/providers/glesys/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
similarity index 100%
rename from labs/glesys/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
rename to providers/glesys/src/main/resources/META-INF/services/org.jclouds.providers.ProviderMetadata
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncApiTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncApiTest.java
new file mode 100644
index 0000000..8f51ddb
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/GleSYSAsyncApiTest.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.rest.internal.BaseAsyncApiTest;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests behavior of {@code GleSYSAsyncApi}
+ * 
+ * @author Adrian Cole
+ */
+// NOTE:without testName, this will not call @Before* and fail w/NPE during
+// surefire
+@Test(groups = "unit", testName = "GleSYSAsyncApiTest")
+public class GleSYSAsyncApiTest extends BaseAsyncApiTest<GleSYSAsyncApi> {
+   private GleSYSAsyncApi asyncApi;
+   private GleSYSApi syncApi;
+
+   @Override
+   public ProviderMetadata createProviderMetadata() {
+      return new GleSYSProviderMetadata();
+   }
+   
+   public void testSync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
+      assert syncApi.getServerApi() != null;
+      assert syncApi.getIpApi() != null;
+      assert syncApi.getDomainApi() != null;
+      assert syncApi.getArchiveApi() != null;
+   }
+
+   public void testAsync() throws SecurityException, NoSuchMethodException, InterruptedException, ExecutionException {
+      assert asyncApi.getServerApi() != null;
+      assert asyncApi.getIpApi() != null;
+      assert asyncApi.getDomainApi() != null;
+      assert asyncApi.getArchiveApi() != null;
+   }
+
+   @Override
+   protected TypeLiteral<RestAnnotationProcessor<GleSYSAsyncApi>> createTypeLiteral() {
+      return new TypeLiteral<RestAnnotationProcessor<GleSYSAsyncApi>>() {
+      };
+   }
+
+   @BeforeClass
+   @Override
+   protected void setupFactory() throws IOException {
+      super.setupFactory();
+      asyncApi = injector.getInstance(GleSYSAsyncApi.class);
+      syncApi = injector.getInstance(GleSYSApi.class);
+   }
+
+   @Override
+   protected void checkFilters(HttpRequest request) {
+
+   }
+}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/GleSYSErrorHandlerTest.java
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/GleSYSProviderTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/GleSYSProviderTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/GleSYSProviderTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/GleSYSProviderTest.java
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapterExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapterExpectTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapterExpectTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceAdapterExpectTest.java
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSComputeServiceLiveTest.java
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentExpectTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentExpectTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentExpectTest.java
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentLiveTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentLiveTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSExperimentLiveTest.java
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java
new file mode 100644
index 0000000..59d9e77
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/compute/GleSYSTemplateBuilderLiveTest.java
@@ -0,0 +1,103 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.compute;
+
+import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
+import static org.jclouds.compute.util.ComputeServiceUtils.getSpace;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.Set;
+
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.domain.OsFamilyVersion64Bit;
+import org.jclouds.compute.domain.Template;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest;
+import org.jclouds.glesys.compute.options.GleSYSTemplateOptions;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * 
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "GleSYSTemplateBuilderLiveTest")
+public class GleSYSTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
+
+   public GleSYSTemplateBuilderLiveTest() {
+      provider = "glesys";
+   }
+
+   // / allows us to break when a new os is added
+   @Override
+   protected Predicate<OsFamilyVersion64Bit> defineUnsupportedOperatingSystems() {
+      return Predicates.not(new Predicate<OsFamilyVersion64Bit>() {
+
+         @Override
+         public boolean apply(OsFamilyVersion64Bit input) {
+            switch (input.family) {
+            case UBUNTU:
+               return input.version.equals("")
+                     || input.version.equals("10.04")
+                     || input.version.equals("12.04")
+                     || ((input.version.equals("8.04") || input.version.equals("11.04") || input.version
+                           .equals("10.10")) && input.is64Bit);
+            case DEBIAN:
+               return input.version.equals("") || input.version.matches("[56].0");
+            case FEDORA:
+               return input.version.equals("") || input.version.equals("13") || input.version.equals("15");
+            case CENTOS:
+               return input.version.equals("") || input.version.equals("5") || input.version.equals("5.5")
+                     || input.version.equals("5.0") || input.version.equals("6.0");
+            case WINDOWS:
+               return (input.version.equals("") || input.version.equals("2008")
+                     || input.version.equals("2008 R2")) && input.is64Bit;
+            default:
+               return false;
+            }
+         }
+
+      });
+   }
+
+   @Test
+   public void testDefaultTemplateBuilder() throws IOException {
+      Template defaultTemplate = view.getComputeService().templateBuilder().build();
+      assertEquals(defaultTemplate.getImage().getId(), "Ubuntu 12.04 x64");
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "12.04");
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
+      assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
+      assertEquals(defaultTemplate.getHardware().getRam(), 768);
+      assertEquals(defaultTemplate.getHardware().getHypervisor(), "Xen");
+      assertEquals(getSpace(defaultTemplate.getHardware()), 5.0d);
+      assertEquals(defaultTemplate.getHardware().getVolumes().get(0).getType(), Volume.Type.LOCAL);
+      // test that we bound the correct templateoptions in guice
+      assertEquals(defaultTemplate.getOptions().getClass(), GleSYSTemplateOptions.class);
+   }
+
+   @Override
+   protected Set<String> getIso3166Codes() {
+      return ImmutableSet.<String> of("NL-NH", "SE-N", "US-NY", "SE-AB");
+   }
+}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageNameTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageNameTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageNameTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ParseOsFamilyVersion64BitFromImageNameTest.java
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java
new file mode 100644
index 0000000..771bcb2
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerDetailsToNodeMetadataTest.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.compute.functions;
+
+import static org.jclouds.io.Payloads.newUrlEncodedFormPayload;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.compute.domain.HardwareBuilder;
+import org.jclouds.compute.domain.NodeMetadata;
+import org.jclouds.compute.domain.NodeMetadata.Status;
+import org.jclouds.compute.domain.NodeMetadataBuilder;
+import org.jclouds.compute.domain.OperatingSystem;
+import org.jclouds.compute.domain.OsFamily;
+import org.jclouds.compute.domain.Processor;
+import org.jclouds.compute.domain.Volume;
+import org.jclouds.compute.domain.internal.VolumeImpl;
+import org.jclouds.glesys.compute.internal.BaseGleSYSComputeServiceExpectTest;
+import org.jclouds.glesys.features.ServerApiExpectTest;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+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.ImmutableSet;
+
+/**
+ * TODO
+ * 
+ */
+@Test(groups = "unit", testName = "ServerDetailsToNodeMetadataTest")
+public class ServerDetailsToNodeMetadataTest extends BaseGleSYSComputeServiceExpectTest {
+
+   @Test
+   public void testServerDetailsRequest() {
+
+      ServerDetailsToNodeMetadata toTest = injectorForKnownArgumentsAndConstantPassword(
+            ImmutableMap
+                  .<HttpRequest, HttpResponse> builder()
+                  .put(HttpRequest
+                        .builder()
+                        .method("POST")
+                        .endpoint("https://api.glesys.com/server/details/format/json")
+                        .addHeader("Accept", "application/json")
+                        .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                        .payload(
+                              newUrlEncodedFormPayload(ImmutableMultimap.<String, String> builder()
+                                    .put("serverid", "xm3276891").build())).build(),
+                        HttpResponse
+                              .builder()
+                              .statusCode(200)
+                              .payload(payloadFromResource("/server_details.json"))
+                              .build()).build()
+
+      ).getInstance(ServerDetailsToNodeMetadata.class);
+
+      NodeMetadata actual = toTest.apply(ServerApiExpectTest.expectedServerDetails());
+      assertNotNull(actual);
+
+      assertEquals(
+            actual.toString(),
+            new NodeMetadataBuilder()
+                  .ids("vz1840356")
+                  .name("glesys-s")
+                  .hostname("glesys-s")
+                  .group("glesys")
+                  .imageId("Ubuntu 10.04 LTS 32-bit")
+                  .operatingSystem(
+                        OperatingSystem.builder().name("Ubuntu 10.04 LTS 32-bit").family(OsFamily.UBUNTU).version("10.04")
+                              .is64Bit(false).description("Ubuntu 10.04 LTS 32-bit").build())
+                  .publicAddresses(ImmutableSet.of("31.192.231.254"))
+                  .hardware(
+                        new HardwareBuilder().ids("vz1840356").ram(512)
+                              .processors(ImmutableList.of(new Processor(1, 1.0)))
+                              .volumes(ImmutableList.<Volume> of(new VolumeImpl(5f, true, true))).hypervisor("OpenVZ")
+                              .build()).status(Status.RUNNING).build().toString());
+   }
+}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerSpecToHardwareTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerSpecToHardwareTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerSpecToHardwareTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/compute/functions/ServerSpecToHardwareTest.java
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/internal/BaseGleSYSComputeServiceExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/internal/BaseGleSYSComputeServiceExpectTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/compute/internal/BaseGleSYSComputeServiceExpectTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/compute/internal/BaseGleSYSComputeServiceExpectTest.java
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptionsTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptionsTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptionsTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/compute/options/GleSYSTemplateOptionsTest.java
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiExpectTest.java
new file mode 100644
index 0000000..f8a3009
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiExpectTest.java
@@ -0,0 +1,205 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.jclouds.glesys.domain.Archive;
+import org.jclouds.glesys.domain.ArchiveAllowedArguments;
+import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Tests parsing of {@code ArchiveAsyncApi}
+ *
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "ArchiveApiExpectTest")
+public class ArchiveApiExpectTest extends BaseGleSYSApiExpectTest {
+
+   public void testListArchivesWhenReponseIs2xx() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_list.json")).build())
+            .getArchiveApi();
+
+      Set<Archive> expected = ImmutableSet.of(
+            Archive.builder().username("xxxxx_test1").freeSize("20 GB").totalSize("30 GB").locked(false).build());
+
+      assertEquals(api.list().toImmutableSet(), expected);
+   }
+
+   public void testListArchivesWhenResponseIs4xxReturnsEmpty() {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build()).getArchiveApi();
+
+      assertTrue(api.list().isEmpty());
+   }
+
+   public void testArchiveDetailsWhenResponseIs2xx() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/details/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("username", "xxxxxx_test1").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build())
+            .getArchiveApi();
+
+      assertEquals(api.get("xxxxxx_test1"), detailsInArchiveDetails());
+   }
+
+   private Archive detailsInArchiveDetails() {
+      return Archive.builder().username("xxxxxx_test1").freeSize("30 GB").totalSize("30 GB").locked(false).build();
+   }
+
+   public void testArchiveDetailsWhenResponseIs4xxReturnsNull() {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/details/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("username", "xxxxxx_test1").build(),
+            HttpResponse.builder().statusCode(404).build())
+            .getArchiveApi();
+      assertNull(api.get("xxxxxx_test1"));
+   }
+
+   public void testCreateArchiveWhenResponseIs2xx() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/create/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParams(ImmutableMultimap.<String, String>builder()
+                             .put("username", "xxxxxx_test1")
+                             .put("size", "5")
+                             .put("password", "somepass").build()).build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build()).getArchiveApi();
+      assertEquals(api.createWithCredentialsAndSize("xxxxxx_test1", "somepass", 5), detailsInArchiveDetails());
+   }
+
+   public void testDeleteArchiveWhenResponseIs2xx() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/delete/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("username", "xxxxxx_test1").build(),
+            HttpResponse.builder().statusCode(200).build()).getArchiveApi();
+
+      api.delete("xxxxxx_test1");
+   }
+
+   @Test(expectedExceptions = {HttpResponseException.class})
+   public void testDeleteArchiveWhenResponseIs4xxThrows() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/delete/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("username", "xxxxxx_test1").build(),
+            HttpResponse.builder().statusCode(402).build()).getArchiveApi();
+      api.delete("xxxxxx_test1");
+   }
+
+   public void testResizeArchiveWhenResponseIs2xx() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/resize/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("username", "username1")
+                       .addFormParam("size", "5").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build()).getArchiveApi();
+
+      assertEquals(api.resize("username1", 5), detailsInArchiveDetails());
+   }
+
+   @Test(expectedExceptions = {ResourceNotFoundException.class})
+   public void testResizeArchiveWhenResponseIs4xxThrows() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/archive/resize/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("username", "username1")
+                       .addFormParam("size", "5").build(),
+            HttpResponse.builder().statusCode(404).build()).getArchiveApi();
+
+      api.resize("username1", 5);
+   }
+
+   public void testChangeArchivePasswordWhenResponseIs2xx() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST")
+                       .endpoint("https://api.glesys.com/archive/changepassword/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("username", "username")
+                       .addFormParam("password", "newpass").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_details.json")).build()).getArchiveApi();
+      
+      assertEquals(api.changePassword("username", "newpass"), detailsInArchiveDetails());
+   }
+
+   @Test(expectedExceptions = {ResourceNotFoundException.class})
+   public void testChangeArchivePasswordWhenResponseIs4xxThrows() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST")
+                  .endpoint("https://api.glesys.com/archive/changepassword/format/json")
+                  .addHeader("Accept", "application/json")
+                  .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                  .addFormParam("username", "username")
+                  .addFormParam("password", "newpass").build(),
+            HttpResponse.builder().statusCode(404).build()).getArchiveApi();
+
+      api.changePassword("username", "newpass");
+   }
+
+   public void testGetArchiveAllowedArgumentsWhenResponseIs2xx() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET")
+                  .endpoint("https://api.glesys.com/archive/allowedarguments/format/json")
+                  .addHeader("Accept", "application/json")
+                  .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/archive_allowed_arguments.json")).build()).getArchiveApi();
+      ArchiveAllowedArguments expected = ArchiveAllowedArguments.builder().archiveSizes(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000).build();
+
+      assertEquals(api.getAllowedArguments(), expected);
+   }
+
+   public void testGetArchiveAllowedArguments4xxWhenResponseIs2xx() throws Exception {
+      ArchiveApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET")
+                  .endpoint("https://api.glesys.com/archive/allowedarguments/format/json")
+                  .addHeader("Accept", "application/json")
+                  .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build()).getArchiveApi();
+
+      assertNull(api.getAllowedArguments());
+   }
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiLiveTest.java
new file mode 100644
index 0000000..d60d785
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/ArchiveApiLiveTest.java
@@ -0,0 +1,122 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.glesys.domain.Archive;
+import org.jclouds.glesys.domain.ArchiveAllowedArguments;
+import org.jclouds.glesys.internal.BaseGleSYSApiLiveTest;
+import org.jclouds.predicates.RetryablePredicate;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Tests behavior of {@code ArchiveApi}
+ *
+ * @author Adam Lowe
+ */
+@Test(groups = "live", testName = "ArchiveApiLiveTest", singleThreaded = true)
+public class ArchiveApiLiveTest extends BaseGleSYSApiLiveTest {
+
+   @BeforeClass(groups = { "integration", "live" })
+   public void setupContext() {
+      super.setupContext();
+      
+      api = gleContext.getApi().getArchiveApi();
+      archiveUser = gleContext.getIdentity().toLowerCase() + "_test9";
+      archiveCounter = new RetryablePredicate<Integer>(
+            new Predicate<Integer>() {
+               public boolean apply(Integer value){
+                  return api.list().size() == value;
+               }
+            }, 30, 1, TimeUnit.SECONDS);
+   }
+   
+   @AfterClass(groups = { "integration", "live" })
+   protected void tearDownContext() {
+      int before = api.list().size();
+      api.delete(archiveUser);
+      assertTrue(archiveCounter.apply(before - 1));
+
+      super.tearDownContext();
+   }
+
+   private ArchiveApi api;
+   private String archiveUser;
+   private RetryablePredicate<Integer> archiveCounter;
+
+   @Test
+   public void testAllowedArguments() throws Exception {
+      ArchiveAllowedArguments args = api.getAllowedArguments();
+      assertNotNull(args);
+      assertNotNull(args.getSizes());
+      assertTrue(args.getSizes().size() > 0);
+      
+      for (int size : args.getSizes()) {
+         assertTrue(size > 0);
+      }
+   }
+   
+   @Test
+   public void testCreateArchive() throws Exception {
+      try {
+         api.delete(archiveUser);
+      } catch(Exception ex) {
+      }
+      
+      int before = api.list().size();
+      
+      api.createWithCredentialsAndSize(archiveUser, "password", 10);
+
+      assertTrue(archiveCounter.apply(before + 1));
+   }
+
+   @Test(dependsOnMethods = "testCreateArchive")
+   public void testArchiveDetails() throws Exception {
+      Archive details = api.get(archiveUser);
+      assertEquals(details.getUsername(), archiveUser);
+   }
+
+   @Test(dependsOnMethods = "testCreateArchive")
+   public void testChangePassword() throws Exception {
+      api.changePassword(archiveUser, "newpassword");      
+      // TODO assert something useful!
+   }
+
+   @Test(dependsOnMethods = "testCreateArchive")
+   public void testResizeArchive() throws Exception {
+      api.resize(archiveUser, 20);
+
+      assertTrue(new RetryablePredicate<String>(
+            new Predicate<String>() {
+               public boolean apply(String value){
+                  return api.get(archiveUser) != null && value.equals(api.get(archiveUser).getTotalSize());
+               }
+            }, 30, 1, TimeUnit.SECONDS).apply("20 GB"));
+   }
+
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/DomainApiExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/DomainApiExpectTest.java
new file mode 100644
index 0000000..93230fa
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/DomainApiExpectTest.java
@@ -0,0 +1,318 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.Domain;
+import org.jclouds.glesys.domain.DomainRecord;
+import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
+import org.jclouds.glesys.options.AddDomainOptions;
+import org.jclouds.glesys.options.DomainOptions;
+import org.jclouds.glesys.options.UpdateRecordOptions;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/**
+ * Tests annotation parsing of {@code DomainAsyncApi}
+ *
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "DomainApiExpectTest")
+public class DomainApiExpectTest extends BaseGleSYSApiExpectTest {
+   
+   public void testListDomainsWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/domain_list.json")).build()).getDomainApi();
+
+      Domain expected =
+            Domain.builder().domainName("testglesys.jclouds.org").createTime(dateService.iso8601SecondsDateParse("2012-01-31T12:19:03+01:00")).build();
+
+      Domain actual = Iterables.getOnlyElement(api.list());
+      assertEquals(expected.getName(), actual.getName());
+      assertEquals(expected.getCreateTime(), actual.getCreateTime());
+   }
+
+   public void testListDomainsWhenResponseIs4xxReturnsEmpty() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build()).getDomainApi();
+
+      assertTrue(api.list().isEmpty());
+   }
+
+   public void testListDomainRecordsWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/listrecords/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "testglesys.jclouds.org").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/domain_list_records.json")).build()).getDomainApi();
+
+      Set<DomainRecord> expected = ImmutableSet.of(
+            DomainRecord.builder().id("224538").domainname("testglesys.jclouds.org").host("@").type("NS").data("ns1.namesystem.se.").ttl(3600).build(),
+            DomainRecord.builder().id("224539").domainname("testglesys.jclouds.org").host("@").type("NS").data("ns2.namesystem.se.").ttl(3600).build(),
+            DomainRecord.builder().id("224540").domainname("testglesys.jclouds.org").host("@").type("NS").data("ns3.namesystem.se.").ttl(3600).build(),
+            DomainRecord.builder().id("224541").domainname("testglesys.jclouds.org").host("@").type("A").data("127.0.0.1").ttl(3600).build(),
+            DomainRecord.builder().id("224542").domainname("testglesys.jclouds.org").host("www").type("A").data("127.0.0.1").ttl(3600).build(),
+            DomainRecord.builder().id("224543").domainname("testglesys.jclouds.org").host("mail").type("A").data("79.99.4.40").ttl(3600).build(),
+            DomainRecord.builder().id("224544").domainname("testglesys.jclouds.org").host("@").type("MX").data("10 mx01.glesys.se.").ttl(3600).build(),
+            DomainRecord.builder().id("224545").domainname("testglesys.jclouds.org").host("@").type("MX").data("20 mx02.glesys.se.").ttl(3600).build(),
+            DomainRecord.builder().id("224546").domainname("testglesys.jclouds.org").host("@").type("TXT").data("v=spf1 include:spf.glesys.se -all").ttl(3600).build()
+      );
+
+      Set<DomainRecord> actual = api.listRecords("testglesys.jclouds.org");
+
+      assertEquals(actual, expected);
+
+      for (DomainRecord result : actual) {
+         for (DomainRecord expect : expected) {
+            if (result.equals(expect)) {
+               assertEquals(result.toString(), expect.toString(), "Deep comparison using toString() failed!");
+            }
+         }
+      }
+   }
+
+   public void testListDomainRecordsWhenResponseIs4xxReturnsEmpty() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build()).getDomainApi();
+
+      assertTrue(api.list().isEmpty());
+   }
+
+   public void testAddDomainRecordsWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/addrecord/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "jclouds.org")
+                       .addFormParam("type", "A")
+                       .addFormParam("host", "jclouds.org")
+                       .addFormParam("data", "").build(),
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/domain_record.json", MediaType.APPLICATION_JSON)).build())
+            .getDomainApi();
+
+      assertEquals(api.createRecord("jclouds.org", "jclouds.org", "A", ""), recordInDomainRecord());
+   }
+
+   protected DomainRecord recordInDomainRecord() {
+      return DomainRecord.builder().id("256151").domainname("cl13016-domain.jclouds.org").host("test").type("A").data("127.0.0.1").ttl(3600).build();
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testAddDomainRecordsWhenResponseIs4xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/addrecord/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "jclouds.org")
+                       .addFormParam("type", "A")
+                       .addFormParam("host", "jclouds.org")
+                       .addFormParam("data", "").build(),
+            HttpResponse.builder().statusCode(404).build()).getDomainApi();
+
+      api.createRecord("jclouds.org", "jclouds.org", "A", "");
+   }
+
+   public void testUpdateDomainRecordsWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/updaterecord/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("recordid", "256151")
+                       .addFormParam("host", "somehost")
+                       .addFormParam("ttl", "1800").build(),
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/domain_record.json", MediaType.APPLICATION_JSON)).build())
+            .getDomainApi();
+
+      assertEquals(api.updateRecord("256151", UpdateRecordOptions.Builder.host("somehost").ttl(1800)), recordInDomainRecord());
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testUpdateDomainRecordsWhenResponseIs4xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+               HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/updaterecord/format/json")
+                          .addHeader("Accept", "application/json")
+                          .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                          .addFormParam("recordid", "256151")
+                          .addFormParam("host", "somehost")
+                          .addFormParam("ttl", "1800").build(),
+            HttpResponse.builder().statusCode(404).build()).getDomainApi();
+
+      api.updateRecord("256151", UpdateRecordOptions.Builder.host("somehost").ttl(1800));
+   }
+
+   public void testDeleteDomainRecordsWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/deleterecord/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("recordid", "256151").build(),
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/domain_record.json", MediaType.APPLICATION_JSON)).build())
+            .getDomainApi();
+
+      api.deleteRecord("256151");
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testDeleteDomainRecordsWhenResponseIs4xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/deleterecord/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("recordid", "256151").build(),
+            HttpResponse.builder().statusCode(404).build()).getDomainApi();
+
+      api.deleteRecord("256151");
+   }
+
+   public void testGetDomainWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/details/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "cl66666_x").build(),
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/domain_details.json", MediaType.APPLICATION_JSON)).build())
+            .getDomainApi();
+
+      assertEquals(api.get("cl66666_x"), domainInDomainDetails());
+   }
+
+
+   public void testGetDomainWhenResponseIs4xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/details/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "cl66666_x").build(),
+            HttpResponse.builder().statusCode(404).build())
+            .getDomainApi();
+
+      assertNull(api.get("cl66666_x"));
+   }
+
+   protected Domain domainInDomainDetails() {
+      return Domain.builder().domainName("cl13016-domain.jclouds.org").createTime(dateService.iso8601SecondsDateParse("2012-06-24T11:52:49+02:00")).recordCount(9).build();
+   }
+
+   public void testAddDomainWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/add/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "cl66666_x").build(),
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/domain_details.json", MediaType.APPLICATION_JSON)).build())
+            .getDomainApi();
+
+      assertEquals(api.create("cl66666_x"), domainInDomainDetails());
+   }
+
+   public void testAddDomainWithOptsWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/add/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "cl66666_x")
+                       .addFormParam("primarynameserver", "ns1.somewhere.x")
+                       .addFormParam("expire", "1")
+                       .addFormParam("minimum", "1")
+                       .addFormParam("refresh", "1")
+                       .addFormParam("responsibleperson", "Tester.")
+                       .addFormParam("retry", "1")
+                       .addFormParam("ttl", "1").build(),
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/domain_details.json", MediaType.APPLICATION_JSON)).build())
+            .getDomainApi();
+      AddDomainOptions options = (AddDomainOptions) AddDomainOptions.Builder.primaryNameServer("ns1.somewhere.x")
+            .expire(1).minimum(1).refresh(1).responsiblePerson("Tester").retry(1).ttl(1);
+
+      assertEquals(api.create("cl66666_x", options), domainInDomainDetails());
+   }
+
+   public void testUpdateDomainWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/edit/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "x")
+                       .addFormParam("expire", "1").build(),
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/domain_details.json", MediaType.APPLICATION_JSON)).build())
+            .getDomainApi();
+
+      assertEquals(api.update("x", DomainOptions.Builder.expire(1)), domainInDomainDetails());
+   }
+
+   @Test(expectedExceptions = {ResourceNotFoundException.class})
+   public void testUpdateDomainWhenResponseIs4xxThrows() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/edit/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "x")
+                       .addFormParam("expire", "1").build(),
+            HttpResponse.builder().statusCode(404).build()).getDomainApi();
+
+      api.update("x", DomainOptions.Builder.expire(1));
+   }
+
+   public void testDeleteDomainWhenResponseIs2xx() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/delete/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "x").build(),
+            HttpResponse.builder().statusCode(200).build()).getDomainApi();
+
+      api.delete("x");
+   }
+
+   @Test(expectedExceptions = {ResourceNotFoundException.class})
+   public void testDeleteDomainWhenResponseIs4xxThrows() throws Exception {
+      DomainApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/domain/delete/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "x").build(),
+            HttpResponse.builder().statusCode(404).build()).getDomainApi();
+
+      api.delete("x");
+   }
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/DomainApiLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/DomainApiLiveTest.java
new file mode 100644
index 0000000..3a25d26
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/DomainApiLiveTest.java
@@ -0,0 +1,162 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.glesys.domain.Domain;
+import org.jclouds.glesys.domain.DomainRecord;
+import org.jclouds.glesys.internal.BaseGleSYSApiLiveTest;
+import org.jclouds.glesys.options.DomainOptions;
+import org.jclouds.glesys.options.UpdateRecordOptions;
+import org.jclouds.predicates.RetryablePredicate;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Tests behavior of {@code DomainApi}
+ *
+ * @author Adam Lowe
+ */
+@Test(groups = "live", testName = "DomainApiLiveTest", singleThreaded = true)
+public class DomainApiLiveTest extends BaseGleSYSApiLiveTest {
+   public String testDomain;
+
+   @BeforeClass(groups = { "integration", "live" })
+   public void setupContext() {
+      super.setupContext();
+      testDomain =  identity.toLowerCase() + "-domain.jclouds.org";
+      api = gleContext.getApi().getDomainApi();
+      domainCounter = new RetryablePredicate<Integer>(
+            new Predicate<Integer>() {
+               public boolean apply(Integer value) {
+                  return api.list().size() == value;
+               }
+            }, 30, 1, TimeUnit.SECONDS);
+      recordCounter = new RetryablePredicate<Integer>(
+            new Predicate<Integer>() {
+               public boolean apply(Integer value) {
+                  return api.listRecords(testDomain).size() == value;
+               }
+            }, 30, 1, TimeUnit.SECONDS);
+
+      try {
+         api.delete(testDomain);
+      } catch (Exception ex) {
+      }
+      
+      createDomain(testDomain);
+   }
+
+   @AfterClass(groups = { "integration", "live" })
+   public void tearDownContext() {
+      int before = api.list().size();
+      api.delete(testDomain);
+      assertTrue(domainCounter.apply(before - 1));
+   
+      super.tearDownContext();
+   }
+
+   private DomainApi api;
+   private RetryablePredicate<Integer> domainCounter;
+   private RetryablePredicate<Integer> recordCounter;
+
+   @Test
+   public void testGetDomain() throws Exception {
+      Domain domain = api.get(testDomain);
+      assertNotNull(domain);
+      assertEquals(domain.getName(), testDomain);
+      assertNotNull(domain.getCreateTime());
+   }
+   
+   @Test
+   public void testUpdateDomain() throws Exception {
+      api.update(testDomain, DomainOptions.Builder.responsiblePerson("another-tester.jclouds.org."));
+      Domain domain = api.get(testDomain);
+      assertEquals(domain.getResponsiblePerson(), "another-tester.jclouds.org.");
+   }
+
+   @Test
+   public void testCreateRecord() throws Exception {
+      int before = api.listRecords(testDomain).size();
+
+      api.createRecord(testDomain, "test", "A", "127.0.0.1");
+
+      assertTrue(recordCounter.apply(before + 1));
+
+      for(DomainRecord record : api.listRecords(testDomain)) {
+         if ("test".equals(record.getHost())) {
+            assertEquals(record.getType(), "A");
+            assertEquals(record.getData(), "127.0.0.1");
+         }
+      }
+   }
+
+   @Test
+   public void testUpdateRecord() throws Exception {
+      int before = api.listRecords(testDomain).size();
+
+      api.createRecord(testDomain, "testeditbefore", "A", "127.0.0.1");
+
+      assertTrue(recordCounter.apply(before + 1));
+
+      String recordId = null;
+      for(DomainRecord record : api.listRecords(testDomain)) {
+         if ("testeditbefore".equals(record.getHost())) {
+            assertEquals(record.getType(), "A");
+            assertEquals(record.getData(), "127.0.0.1");
+            recordId = record.getId();
+         }
+      }
+
+      assertNotNull(recordId);
+
+      api.updateRecord(recordId, UpdateRecordOptions.Builder.host("testeditafter"));
+
+      boolean found = false;
+      for(DomainRecord record : api.listRecords(testDomain)) {
+         if (recordId.equals(record.getId())) {
+            assertEquals(record.getHost(), "testeditafter");
+            assertEquals(record.getType(), "A");
+            assertEquals(record.getData(), "127.0.0.1");
+            found = true;
+         }
+      }
+      assertTrue(found);
+   }
+
+   @Test
+   public void testDeleteRecord() throws Exception {
+      Set<DomainRecord> domainRecords = api.listRecords(testDomain);
+
+      int before = domainRecords.size();
+      
+      api.deleteRecord(domainRecords.iterator().next().getId());
+
+      assertTrue(recordCounter.apply(before - 1));
+   }
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAccountApiExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAccountApiExpectTest.java
new file mode 100644
index 0000000..30adf0d
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAccountApiExpectTest.java
@@ -0,0 +1,267 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.EmailAccount;
+import org.jclouds.glesys.domain.EmailAlias;
+import org.jclouds.glesys.domain.EmailOverview;
+import org.jclouds.glesys.domain.EmailOverviewDomain;
+import org.jclouds.glesys.domain.EmailOverviewSummary;
+import org.jclouds.glesys.domain.EmailQuota;
+import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
+import org.jclouds.glesys.options.UpdateAccountOptions;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/**
+ * Tests annotation parsing of {@code EmailAccountApi}
+ *
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "EmailAccountAsyncApiTest")
+public class EmailAccountApiExpectTest extends BaseGleSYSApiExpectTest {
+
+   public void testListWhenResponseIs2xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "cl13016.test.jclouds.org").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_list.json")).build()).getEmailAccountApi();
+
+      EmailAccount.Builder<?> builder = EmailAccount.builder().quota(EmailQuota.builder().max(200).unit("MB").build()).antispamLevel(3).antiVirus(true).autoRespond(false).autoRespondSaveEmail(true);
+      Set<EmailAccount> expected =
+            ImmutableSet.of(
+                  builder.account("test1@cl13016.test.jclouds.org").antispamLevel(3)
+                        .created(dateService.iso8601SecondsDateParse("2012-06-24T11:53:45+02:00")).build(),
+                  builder.account("test@cl13016.test.jclouds.org").antispamLevel(3)
+                        .created(dateService.iso8601SecondsDateParse("2012-06-21T11:26:09+02:00"))
+                        .modified(dateService.iso8601SecondsDateParse("2012-06-24T11:53:48+02:00")).build()
+            );
+
+      Set<EmailAccount> actual = api.listDomain("cl13016.test.jclouds.org").toImmutableSet();
+      assertEquals(actual, expected);
+      assertEquals(Iterables.get(actual, 0).toString(), Iterables.get(expected, 0).toString());
+   }
+
+   public void testListWhenResponseIs404IsEmpty() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/list/format/json")
+                  .addHeader("Accept", "application/json")
+                  .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                  .addFormParam("domainname", "test").build(),
+            HttpResponse.builder().statusCode(404).build()).getEmailAccountApi();
+
+      assertTrue(api.listDomain("test").isEmpty());
+   }
+
+   public void testListAliasesWhenResponseIs2xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "cl13016.test.jclouds.org").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_list.json")).build()).getEmailAccountApi();
+
+      EmailAlias expected = EmailAlias.builder().alias("test2@cl13016.test.jclouds.org").forwardTo("test2@cl13016.test.jclouds.org").build();
+      EmailAlias actual = Iterables.getOnlyElement(api.listAliasesInDomain("cl13016.test.jclouds.org"));
+      assertEquals(actual, expected);
+   }
+
+   public void testListAliasesWhenResponseIs404IsEmpty() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("domainname", "test").build(),
+            HttpResponse.builder().statusCode(404).build()).getEmailAccountApi();
+
+      assertTrue(api.listAliasesInDomain("test").isEmpty());
+   }
+
+   public void testOverviewWhenResponseIs2xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/overview/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/email_overview.json")).build()).getEmailAccountApi();
+
+      EmailOverviewSummary summary = EmailOverviewSummary.builder().accounts(2).maxAccounts(50).aliases(1).maxAliases(1000).build();
+      EmailOverviewDomain domain = EmailOverviewDomain.builder().domain("cl13016.test.jclouds.org").accounts(2).aliases(0).build();
+      EmailOverview expected = EmailOverview.builder().summary(summary).domains(domain).build();
+
+      assertEquals(api.getOverview(), expected);
+   }
+
+   public void testOverviewWhenResponseIs404ReturnsNull() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/overview/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build()).getEmailAccountApi();
+
+      assertNull(api.getOverview());
+   }
+
+   public void testCreateAccountWhenResponseIs2xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/createaccount/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("emailaccount", "test@jclouds.org")
+                       .addFormParam("password", "newpass").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/email_details.json", MediaType.APPLICATION_JSON)).build())
+            .getEmailAccountApi();
+
+      assertEquals(api.createWithPassword("test@jclouds.org", "newpass").toString(), getEmailAccountInDetails().toString());
+   }
+
+   public void testUpdateAccountWhenResponseIs2xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/editaccount/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("emailaccount", "test@jclouds.org")
+                       .addFormParam("password", "anotherpass").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/email_details.json", MediaType.APPLICATION_JSON)).build())
+            .getEmailAccountApi();
+
+      assertEquals(api.update("test@jclouds.org", UpdateAccountOptions.Builder.password("anotherpass")).toString(), getEmailAccountInDetails().toString());
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testUpdateAccountWhenResponseIs4xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/editaccount/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("emailaccount", "test@jclouds.org")
+                       .addFormParam("password", "anotherpass").build(),
+            HttpResponse.builder().statusCode(404).build())
+            .getEmailAccountApi();
+
+      assertEquals(api.update("test@jclouds.org", UpdateAccountOptions.Builder.password("anotherpass")).toString(), getEmailAccountInDetails().toString());
+   }
+
+   private EmailAccount getEmailAccountInDetails() {
+      return EmailAccount.builder().account("test@CL13016.jclouds.org")
+            .antispamLevel(3)
+            .antiVirus(true)
+            .autoRespondSaveEmail(true)
+            .created(dateService.iso8601SecondsDateParse("2012-06-20T12:01:01+02:00"))
+            .quota(EmailQuota.builder().max(200).unit("MB").build()).build();
+   }
+
+   @Test(expectedExceptions = {ResourceNotFoundException.class})
+   public void testCreateAccountWhenResponseIs4xxThrows() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/createaccount/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("emailaccount", "test@jclouds.org")
+                       .addFormParam("password", "newpass").build(),
+            HttpResponse.builder().statusCode(404).build()).getEmailAccountApi();
+
+      api.createWithPassword("test@jclouds.org", "newpass");
+   }
+
+   public void testCreateAliasWhenResponseIs2xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/createalias/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("emailalias", "test2@jclouds.org")
+                       .addFormParam("goto", "test@jclouds.org").build(),
+            HttpResponse.builder().statusCode(200).build()).getEmailAccountApi();
+
+      api.createAlias("test2@jclouds.org", "test@jclouds.org");
+   }
+
+   @Test(expectedExceptions = {AuthorizationException.class})
+   public void testCreateAliasWhenResponseIs4xxThrows() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/createalias/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("emailalias", "test2@jclouds.org")
+                       .addFormParam("goto", "test@jclouds.org").build(),
+            HttpResponse.builder().statusCode(401).build()).getEmailAccountApi();
+
+      api.createAlias("test2@jclouds.org", "test@jclouds.org");
+   }
+
+   public void testUpdateAliasWhenResponseIs2xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/editalias/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("emailalias", "test2@jclouds.org")
+                       .addFormParam("goto", "test@jclouds.org").build(),
+            HttpResponse.builder().statusCode(200).build()).getEmailAccountApi();
+
+      api.updateAlias("test2@jclouds.org", "test@jclouds.org");
+   }
+
+   @Test(expectedExceptions = {ResourceNotFoundException.class})
+   public void testUpdateAliasWhenResponseIs4xxThrows() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/editalias/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("emailalias", "test2@jclouds.org")
+                       .addFormParam("goto", "test@jclouds.org").build(),
+            HttpResponse.builder().statusCode(404).build()).getEmailAccountApi();
+
+      api.updateAlias("test2@jclouds.org", "test@jclouds.org");
+   }
+
+   public void testDeleteWhenResponseIs2xx() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/delete/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("email", "test2@jclouds.org").build(),
+            HttpResponse.builder().statusCode(200).build()).getEmailAccountApi();
+
+      api.delete("test2@jclouds.org");
+   }
+
+   public void testDeleteWhenResponseIs4xxOk() throws Exception {
+      EmailAccountApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/email/delete/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("email", "test2@jclouds.org").build(),
+            HttpResponse.builder().statusCode(404).build()).getEmailAccountApi();
+
+      api.delete("test2@jclouds.org");
+   }
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAccountApiLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAccountApiLiveTest.java
new file mode 100644
index 0000000..2fc3bbc
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/EmailAccountApiLiveTest.java
@@ -0,0 +1,168 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.glesys.domain.EmailAccount;
+import org.jclouds.glesys.domain.EmailAlias;
+import org.jclouds.glesys.domain.EmailOverview;
+import org.jclouds.glesys.domain.EmailOverviewDomain;
+import org.jclouds.glesys.internal.BaseGleSYSApiLiveTest;
+import org.jclouds.glesys.options.CreateAccountOptions;
+import org.jclouds.glesys.options.UpdateAccountOptions;
+import org.jclouds.predicates.RetryablePredicate;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
+
+/**
+ * Tests behavior of {@code EmailAccountApi}
+ * 
+ * @author Adam Lowe
+ */
+@Test(groups = "live", testName = "EmailAccountApiLiveTest", singleThreaded = true)
+public class EmailAccountApiLiveTest extends BaseGleSYSApiLiveTest {
+   public EmailAccountApiLiveTest() {
+      hostName = hostName + "-email";
+   }
+
+   @BeforeClass(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      super.setupContext();
+      testDomain = hostName + ".test.jclouds.org";
+      api = gleContext.getApi().getEmailAccountApi();
+      deleteAll();
+
+      createDomain(testDomain);
+
+      emailAccountCounter = new RetryablePredicate<Integer>(new Predicate<Integer>() {
+         public boolean apply(Integer value) {
+            return api.listDomain(testDomain).size() == value;
+         }
+      }, 180, 5, TimeUnit.SECONDS);
+
+      assertTrue(emailAccountCounter.apply(0));
+
+   }
+
+   @AfterClass(groups = { "integration", "live" })
+   @Override
+   public void tearDownContext() {
+      deleteAll();
+      super.tearDownContext();
+   }
+
+   private void deleteAll() {
+      api.delete("test@" + testDomain);
+      api.delete("test1@" + testDomain);
+   }
+
+   private EmailAccountApi api;
+   private String testDomain;
+   private RetryablePredicate<Integer> emailAccountCounter;
+
+   @Test
+   public void testCreateEmail() {
+      api.createWithPassword("test@" + testDomain, "password", CreateAccountOptions.Builder.antiVirus(true)
+               .autorespond(true).autorespondMessage("out of office"));
+
+      assertTrue(emailAccountCounter.apply(1));
+
+      api.createWithPassword("test1@" + testDomain, "password");
+
+      assertTrue(emailAccountCounter.apply(2));
+   }
+
+   @Test(dependsOnMethods = "testCreateEmail")
+   public void testAliases() {
+      assertTrue(api.listAliasesInDomain(testDomain).isEmpty());
+
+      EmailAlias alias = api.createAlias("test2@" + testDomain, "test@" + testDomain);
+      assertEquals(alias.getAlias(), "test2@" + testDomain);
+      assertEquals(alias.getForwardTo(), "test@" + testDomain);
+
+      EmailAlias aliasFromList = Iterables.getOnlyElement(api.listAliasesInDomain(testDomain));
+      assertEquals(aliasFromList, alias);
+
+      EmailOverview overview = api.getOverview();
+      assertTrue(overview.getSummary().getAliases() == 1);
+
+      alias = api.updateAlias("test2@" + testDomain, "test1@" + testDomain);
+      overview = api.getOverview();
+      assertTrue(overview.getSummary().getAliases() == 1);
+
+      aliasFromList = Iterables.getOnlyElement(api.listAliasesInDomain(testDomain));
+      assertEquals(aliasFromList, alias);
+
+      api.delete("test2@" + testDomain);
+      overview = api.getOverview();
+      assertTrue(overview.getSummary().getAliases() == 0);
+   }
+
+   @Test(dependsOnMethods = "testCreateEmail")
+   public void testOverview() throws Exception {
+      EmailOverview overview = api.getOverview();
+      assertNotNull(overview.getSummary());
+      assertTrue(overview.getSummary().getAccounts() > 0);
+      assertTrue(overview.getSummary().getAliases() > -1);
+      assertTrue(overview.getSummary().getMaxAccounts() > 0);
+      assertTrue(overview.getSummary().getMaxAliases() > 0);
+      assertNotNull(overview.gets());
+      assertFalse(overview.gets().isEmpty());
+
+      EmailOverviewDomain domain = EmailOverviewDomain.builder().domain(testDomain).accounts(1).build();
+      assertTrue(overview.gets().contains(domain));
+   }
+
+   @Test(dependsOnMethods = "testCreateEmail")
+   public void testListAccounts() throws Exception {
+      FluentIterable<EmailAccount> accounts = api.listDomain(testDomain);
+      assertTrue(accounts.size() >= 1);
+   }
+
+   @Test(dependsOnMethods = "testCreateEmail")
+   public void testUpdateAccount() throws Exception {
+      FluentIterable<EmailAccount> accounts = api.listDomain(testDomain);
+      for (EmailAccount account : accounts) {
+         if (account.getAccount().equals("test@" + testDomain)) {
+            assertTrue(account.isAntiVirus());
+         }
+      }
+
+      api.update("test@" + testDomain, UpdateAccountOptions.Builder.antiVirus(false));
+
+      accounts = api.listDomain(testDomain);
+      for (EmailAccount account : accounts) {
+         if (account.getAccount().equals("test@" + testDomain)) {
+            assertFalse(account.isAntiVirus());
+         }
+      }
+   }
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/IpApiExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/IpApiExpectTest.java
new file mode 100644
index 0000000..6358d95
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/IpApiExpectTest.java
@@ -0,0 +1,309 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static java.util.Collections.emptySet;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.Cost;
+import org.jclouds.glesys.domain.IpDetails;
+import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
+import org.jclouds.glesys.parse.ParseIpAddressFromResponseTest;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Allows us to test a api via its side effects.
+ *
+ * @author Adrian Cole, Adam Lowe
+ */
+@Test(groups = "unit", testName = "IpApiExpectTest")
+public class IpApiExpectTest extends BaseGleSYSApiExpectTest {
+
+   public void testListIpsWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/listown/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_list_own.json")).build())
+            .getIpApi();
+
+      IpDetails.Builder<?> builder = IpDetails.builder().datacenter("Falkenberg").version4().reserved(true)
+            .platform("OpenVZ")
+            .nameServers("79.99.4.100", "79.99.4.101")
+            .cost(Cost.builder().amount(2.0).currency("EUR").timePeriod("month").build());
+
+      assertEquals(api.list().toString(), ImmutableSet.of(
+            builder.ptr("31-192-230-68-static.serverhotell.net.").address("31.192.230.68").serverId(null).build(),
+            builder.ptr("31-192-231-148-static.serverhotell.net.").address("31.192.231.148").serverId("vz1609110").build()).toString());
+   }
+
+   public void testListIpsWhenResponseIs4xxReturnsEmpty() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/listown/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build()).getIpApi();
+
+      assertTrue(api.list().isEmpty());
+   }
+
+   public void testGetIpDetailsWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/details/ipaddress/31.192.227.113/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_get_details.json")).build())
+            .getIpApi();
+
+      assertEquals(api.get("31.192.227.113"), getIpInIpDetails());
+   }
+
+   protected IpDetails getIpInIpDetails() {
+      return IpDetails.builder().datacenter("Falkenberg").version4()
+            .platform("OpenVZ").ptr("31-192-227-113-static.serverhotell.net.")
+            .nameServers("79.99.4.100", "79.99.4.101")
+            .address("31.192.227.113")
+            .cost(Cost.builder().amount(2.0).currency("EUR").timePeriod("month").build()).build();
+   }
+
+   public void testGetIpDetailsWhenResponseIs4xxReturnsNull() {
+
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/details/ipaddress/31.192.227.37/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build()).getIpApi();
+
+      assertEquals(api.get("31.192.227.37"), null);
+   }
+
+   public void testTakeWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/take/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "46.21.105.186").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_take.json")).build())
+            .getIpApi();
+
+      api.take("46.21.105.186");
+   }
+
+   @Test(expectedExceptions = HttpResponseException.class)
+   public void testTakeWhenResponseIs4xxThrowsResponseException() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/take/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "46.21.105.186").build(),
+            HttpResponse.builder().statusCode(400).build()).getIpApi();
+      api.take("46.21.105.186");
+   }
+
+   public void testReleaseWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/release/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "46.21.105.186").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_release.json")).build())
+            .getIpApi();
+
+      api.release("46.21.105.186");
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testReleaseWhenResponseIs4xxThrowsResponseException() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/release/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "46.21.105.186").build(),
+            HttpResponse.builder().statusCode(404).build())
+            .getIpApi();
+
+      api.release("46.21.105.186");
+   }
+
+   public void testListFreeWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/listfree/ipversion/4/datacenter/Falkenberg/platform/OpenVZ/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/ip_list_free.json")).build())
+            .getIpApi();
+
+      assertEquals(api.listFree(4, "Falkenberg", "OpenVZ").toImmutableSet(), ParseIpAddressFromResponseTest.EXPECTED_IPS);
+   }
+
+   public void testListFreeWhenResponseIs404ReturnsEmptySet() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/ip/listfree/ipversion/6/datacenter/Falkenberg/platform/OpenVZ/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build())
+            .getIpApi();
+
+      assertEquals(api.listFree(6, "Falkenberg", "OpenVZ").toImmutableSet(), emptySet());
+   }
+
+   public void testAddWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/add/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "31.192.227.37")
+                       .addFormParam("serverid", "vz1946889").build(),
+            HttpResponse.builder().statusCode(200).build())
+            .getIpApi();
+
+      api.addToServer("31.192.227.37", "vz1946889");
+   }
+
+   @Test(expectedExceptions = AuthorizationException.class)
+   public void testAddWhenResponseIs4xxThrowsHttpException() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/add/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "31.192.227.37")
+                       .addFormParam("serverid", "vz1946889").build(),
+            HttpResponse.builder().statusCode(401).build())
+            .getIpApi();
+      api.addToServer("31.192.227.37", "vz1946889");
+   }
+
+   public void testRemoveWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/remove/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "31.192.227.37")
+                       .addFormParam("serverid", "vz1946889").build(),
+            HttpResponse.builder().statusCode(200).build())
+            .getIpApi();
+
+      api.removeFromServer("31.192.227.37", "vz1946889");
+   }
+
+   @Test(expectedExceptions = HttpResponseException.class)
+   public void testRemoveWhenResponseIs4xxThrowsHttpException() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/remove/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "31.192.227.37")
+                       .addFormParam("serverid", "vz1946889").build(),
+            HttpResponse.builder().statusCode(400).build())
+            .getIpApi();
+
+      api.removeFromServer("31.192.227.37", "vz1946889");
+   }
+
+   public void testRemoveAndReleaseWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/remove/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("release", "true")
+                       .addFormParam("ipaddress", "31.192.227.37")
+                       .addFormParam("serverid", "vz1946889").build(),
+            HttpResponse.builder().statusCode(200).build())
+            .getIpApi();
+
+      api.removeFromServerAndRelease("31.192.227.37", "vz1946889");
+   }
+
+   @Test(expectedExceptions = HttpResponseException.class)
+   public void testRemoveAndReleaseWhenResponseIs4xxThrowsHttpException() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/remove/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("release", "true")
+                       .addFormParam("ipaddress", "31.192.227.37")
+                       .addFormParam("serverid", "vz1946889").build(),
+            HttpResponse.builder().statusCode(400).build())
+            .getIpApi();
+
+      api.removeFromServerAndRelease("31.192.227.37", "vz1946889");
+   }
+
+   public void testSetPrtWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/setptr/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "31.192.227.37")
+                       .addFormParam("data", "sommeptr.").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/ip_get_details.json", MediaType.APPLICATION_JSON)).build())
+            .getIpApi();
+
+      assertEquals(api.setPtr("31.192.227.37", "sommeptr."), getIpInIpDetails());
+   }
+
+   @Test(expectedExceptions = ResourceNotFoundException.class)
+   public void testSetPtrWhenResponseIs4xxThrowsHttpException() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/setptr/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "31.192.227.37")
+                       .addFormParam("data", "sommeptr.").build(),
+            HttpResponse.builder().statusCode(404).build())
+            .getIpApi();
+
+      api.setPtr("31.192.227.37", "sommeptr.");
+   }
+
+   public void testResetPrtWhenResponseIs2xx() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/resetptr/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "31.192.227.37").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResourceWithContentType("/ip_get_details.json", MediaType.APPLICATION_JSON)).build())
+            .getIpApi();
+
+      assertEquals(api.resetPtr("31.192.227.37"), getIpInIpDetails());
+   }
+
+   @Test(expectedExceptions = AuthorizationException.class)
+   public void testResetPtrWhenResponseIs4xxThrowsHttpException() {
+      IpApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/ip/resetptr/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("ipaddress", "31.192.227.37").build(),
+            HttpResponse.builder().statusCode(401).build())
+            .getIpApi();
+
+      api.resetPtr("31.192.227.37");
+   }
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/IpApiLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/IpApiLiveTest.java
new file mode 100644
index 0000000..aa6c5c3
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/IpApiLiveTest.java
@@ -0,0 +1,198 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.jclouds.glesys.domain.IpDetails;
+import org.jclouds.glesys.internal.BaseGleSYSApiWithAServerLiveTest;
+import org.jclouds.glesys.options.ListIpOptions;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+/**
+ * Tests behavior of {@code IpApi}
+ * 
+ * @author Adrian Cole, Mattias Holmqvist
+ */
+@Test(groups = "live", testName = "IpApiLiveTest", singleThreaded = true)
+public class IpApiLiveTest extends BaseGleSYSApiWithAServerLiveTest {
+   public IpApiLiveTest() {
+      hostName = hostName + "-ip";
+   }
+
+   @BeforeClass(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      super.setupContext();
+      api = gleContext.getApi().getIpApi();
+   }
+
+   @AfterClass(groups = { "integration", "live" })
+   @Override
+   public void tearDownContext() {
+      if (reservedIp != null) {
+         api.release(reservedIp.getAddress());
+      }
+      super.tearDownContext();
+   }
+
+   private IpApi api;
+   private IpDetails reservedIp;
+
+   @Test
+   public void testListFree() throws Exception {
+      FluentIterable<String> freeIps = api.listFree(4, "Falkenberg", "Xen");
+      assertFalse(freeIps.isEmpty());
+   }
+
+   @Test
+   public void reserveIp() throws Exception {
+      FluentIterable<String> openVzIps = api.listFree(4, "Falkenberg", "OpenVZ");
+      assertFalse(openVzIps.isEmpty());
+      reservedIp = api.take(Iterables.get(openVzIps, 0));
+      assertTrue(reservedIp.isReserved());
+      checkOpenVZDefailsInFalkenberg(reservedIp);
+   }
+
+   @Test(dependsOnMethods = "reserveIp")
+   public void reserveAndReleaseIp() throws Exception {
+      IpDetails details = api.release(reservedIp.getAddress());
+      assertEquals(details.getAddress(), reservedIp.getAddress());
+      assertFalse(details.isReserved());
+
+      // reserve an address again!
+      reserveIp();
+   }
+
+   @Test(dependsOnMethods = "reserveIp")
+   public void testList() throws Exception {
+      FluentIterable<IpDetails> ownIps = api.list();
+      assertTrue(ownIps.contains(reservedIp));
+      ownIps = api.list(ListIpOptions.Builder.datacenter(reservedIp.getDatacenter()));
+      assertTrue(ownIps.contains(reservedIp));
+      ownIps = api.list(ListIpOptions.Builder.platform(reservedIp.getPlatform()));
+      assertTrue(ownIps.contains(reservedIp));
+      ownIps = api.list(ListIpOptions.Builder.ipVersion(reservedIp.getVersion()));
+      assertTrue(ownIps.contains(reservedIp));
+
+      ownIps = api.list(ListIpOptions.Builder.datacenter(reservedIp.getDatacenter()),
+               ListIpOptions.Builder.platform(reservedIp.getPlatform()),
+               ListIpOptions.Builder.ipVersion(reservedIp.getVersion()));
+      assertTrue(ownIps.contains(reservedIp));
+
+      ownIps = api.list(ListIpOptions.Builder.serverId("xmthisisnotaserverid"));
+      assertTrue(ownIps.isEmpty());
+   }
+
+   private void checkOpenVZDefailsInFalkenberg(IpDetails ipDetails) {
+      assertEquals(ipDetails.getDatacenter(), "Falkenberg");
+      assertEquals(ipDetails.getPlatform(), "OpenVZ");
+      assertEquals(ipDetails.getVersion(), 4);
+      assertFalse(ipDetails.getPtr().isEmpty());
+      // broadcast, gateway and netmask are null for OpenVZ
+      assertFalse(ipDetails.getNameServers().isEmpty());
+   }
+
+   @Test
+   public void testGetOpenVZDetails() throws Exception {
+      FluentIterable<String> openVzIps = api.listFree(4, "Falkenberg", "OpenVZ");
+      assertFalse(openVzIps.isEmpty());
+      String openVzIp = openVzIps.iterator().next();
+      IpDetails ipDetails = api.get(openVzIp);
+      checkOpenVZDefailsInFalkenberg(ipDetails);
+      assertEquals(ipDetails.getAddress(), openVzIp);
+   }
+
+   @Test
+   public void testGetXenDetails() throws Exception {
+      FluentIterable<String> xenVzIps = api.listFree(4, "Falkenberg", "Xen");
+      assertFalse(xenVzIps.isEmpty());
+      String xenIp = xenVzIps.iterator().next();
+      IpDetails ipDetails = api.get(xenIp);
+      assertEquals(ipDetails.getDatacenter(), "Falkenberg");
+      assertEquals(ipDetails.getPlatform(), "Xen");
+      assertEquals(ipDetails.getVersion(), 4);
+      assertEquals(ipDetails.getAddress(), xenIp);
+      assertFalse(ipDetails.getPtr().isEmpty());
+      assertNotNull(ipDetails.getBroadcast());
+      assertNotNull(ipDetails.getGateway());
+      assertNotNull(ipDetails.getNetmask());
+      assertFalse(ipDetails.getNameServers().isEmpty());
+   }
+
+   @Test(dependsOnMethods = "reserveIp")
+   public void testPtrSetReset() throws Exception {
+      IpDetails original = reservedIp;
+
+      IpDetails modified = api.setPtr(reservedIp.getAddress(), "wibble.");
+      IpDetails modified2 = api.get(reservedIp.getAddress());
+
+      assertEquals(modified.getPtr(), "wibble.");
+      assertEquals(modified2, modified);
+
+      reservedIp = api.resetPtr(reservedIp.getAddress());
+
+      assertEquals(reservedIp, original);
+   }
+
+   @Test(dependsOnMethods = "reserveIp")
+   public void testAddRemove() throws Exception {
+      IpDetails added = api.addToServer(reservedIp.getAddress(), serverId);
+
+      assertEquals(added.getAddress(), reservedIp.getAddress());
+      assertEquals(added.getPtr(), reservedIp.getPtr());
+      assertEquals(added.getServerId(), serverId);
+
+      IpDetails again = api.get(reservedIp.getAddress());
+      assertEquals(again, added);
+
+      IpDetails removed = api.removeFromServer(reservedIp.getAddress(), serverId);
+      assertEquals(removed, added.toBuilder().serverId(null).build());
+
+      assertEquals(removed, reservedIp);
+
+      Set<String> openVzIps = Sets.newHashSet(api.listFree(4, "Falkenberg", "OpenVZ"));
+      openVzIps.remove(reservedIp.getAddress());
+      assertFalse(openVzIps.isEmpty());
+
+      added = api.addToServer(reservedIp.getAddress(), serverId);
+
+      assertEquals(added.getServerId(), serverId);
+
+      removed = api.removeFromServerAndRelease(reservedIp.getAddress(), serverId);
+
+      assertNull(removed.getServerId());
+      assertFalse(removed.isReserved());
+
+      // reserve an address again!
+      reserveIp();
+   }
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/ServerApiExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/ServerApiExpectTest.java
new file mode 100644
index 0000000..f0053ef
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/ServerApiExpectTest.java
@@ -0,0 +1,560 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
+import org.jclouds.glesys.domain.Console;
+import org.jclouds.glesys.domain.Cost;
+import org.jclouds.glesys.domain.Ip;
+import org.jclouds.glesys.domain.OSTemplate;
+import org.jclouds.glesys.domain.ResourceStatus;
+import org.jclouds.glesys.domain.ResourceUsage;
+import org.jclouds.glesys.domain.ResourceUsageInfo;
+import org.jclouds.glesys.domain.ResourceUsageValue;
+import org.jclouds.glesys.domain.Server;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.glesys.domain.ServerSpec;
+import org.jclouds.glesys.domain.ServerStatus;
+import org.jclouds.glesys.domain.ServerUptime;
+import org.jclouds.glesys.internal.BaseGleSYSApiExpectTest;
+import org.jclouds.glesys.options.CloneServerOptions;
+import org.jclouds.glesys.options.CreateServerOptions;
+import org.jclouds.glesys.options.DestroyServerOptions;
+import org.jclouds.glesys.options.UpdateServerOptions;
+import org.jclouds.glesys.options.ServerStatusOptions;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Tests annotation parsing of {@code ServerAsyncApi}
+ *
+ * @author Adrian Cole
+ * @author Adam Lowe
+ */
+@Test(groups = "unit", testName = "ServerAsyncApiTest")
+public class ServerApiExpectTest extends BaseGleSYSApiExpectTest {
+
+   public void testListServersWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(204).payload(payloadFromResource("/server_list.json")).build()).getServerApi();
+      Server expected = Server.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg").platform("OpenVZ").build();
+
+      assertEquals(api.list().toImmutableSet(), ImmutableSet.<Server>of(expected));
+   }
+
+   public void testListServersWhenReponseIs404IsEmpty() {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/list/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(404).build()).getServerApi();
+
+      assertTrue(api.list().isEmpty());
+   }
+
+   public void testGetAllowedArgumentsWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/server/allowedarguments/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(204).payload(payloadFromResource("/server_allowed_arguments.json")).build()).getServerApi();
+
+      Map<String, AllowedArgumentsForCreateServer> expected = new LinkedHashMap<String, AllowedArgumentsForCreateServer>();
+      AllowedArgumentsForCreateServer openvz = AllowedArgumentsForCreateServer.builder()
+            .dataCenters("Amsterdam", "Falkenberg", "New York City", "Stockholm")
+            .memorySizes(128, 256, 512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288)
+            .diskSizes(5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 150)
+            .cpuCores(1, 2, 3, 4, 5, 6, 7, 8)
+            .templates("Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit", "Debian 5.0 32-bit",
+                  "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11", "Fedora Core 11 64-bit",
+                  "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit", "Slackware 12",
+                  "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit")
+            .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
+            .build();
+      AllowedArgumentsForCreateServer xen = AllowedArgumentsForCreateServer.builder()
+            .memorySizes(512, 768, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 14336, 16384)
+            .diskSizes(5, 10, 20, 30, 40, 50, 80, 100, 120, 140, 150, 160, 160, 200, 250, 300)
+            .cpuCores(1, 2, 3, 4, 5, 6, 7, 8)
+            .templates("CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86", "Debian-6 x64",
+                  "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64", "Ubuntu 10.04 LTS 64-bit",
+                  "Ubuntu 10.10 x64", "Ubuntu 11.04 x64", "Windows Server 2008 R2 x64 std",
+                  "Windows Server 2008 R2 x64 web", "Windows Server 2008 x64 web", "Windows Server 2008 x86 web")
+            .transfers(50, 100, 250, 500, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
+            .dataCenters("Falkenberg")
+            .build();
+      expected.put("Xen", xen);
+      expected.put("OpenVZ", openvz);
+      assertEquals(api.getAllowedArgumentsForCreateByPlatform(), expected);
+   }
+
+   public void testGetTemplatesWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("GET").endpoint("https://api.glesys.com/server/templates/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_templates.json")).build()).getServerApi();
+
+      ImmutableSet.Builder<OSTemplate> expectedBuilder = ImmutableSet.builder();
+
+      for (String name : new String[]{"Centos 5", "Centos 5 64-bit", "Centos 6 32-bit", "Centos 6 64-bit",
+            "Debian 5.0 32-bit", "Debian 5.0 64-bit", "Debian 6.0 32-bit", "Debian 6.0 64-bit", "Fedora Core 11",
+            "Fedora Core 11 64-bit", "Gentoo", "Gentoo 64-bit", "Scientific Linux 6", "Scientific Linux 6 64-bit",
+            "Slackware 12", "Ubuntu 10.04 LTS 32-bit", "Ubuntu 10.04 LTS 64-bit", "Ubuntu 11.04 64-bit"}) {
+         expectedBuilder.add(OSTemplate.builder().name(name).minDiskSize(5).minMemSize(128).os("linux").platform("OpenVZ").build());
+      }
+
+      for (String name : new String[]{"CentOS 5.5 x64", "CentOS 5.5 x86", "Centos 6 x64", "Centos 6 x86",
+            "Debian-6 x64", "Debian 5.0.1 x64", "FreeBSD 8.2", "Gentoo 10.1 x64", "Ubuntu 8.04 x64",
+            "Ubuntu 10.04 LTS 64-bit", "Ubuntu 10.10 x64", "Ubuntu 11.04 x64"}) {
+         expectedBuilder.add(OSTemplate.builder().name(name).minDiskSize(5).minMemSize(512)
+               .os(name.startsWith("FreeBSD") ? "freebsd" : "linux").platform("Xen").build());
+      }
+      for (String name : new String[]{"Windows Server 2008 R2 x64 std", "Windows Server 2008 R2 x64 web",
+            "Windows Server 2008 x64 web", "Windows Server 2008 x86 web"}) {
+         expectedBuilder.add(OSTemplate.builder().name(name).minDiskSize(20).minMemSize(1024).os("windows").platform("Xen").build());
+      }
+
+      assertEquals(api.listTemplates().toImmutableSet(), expectedBuilder.build());
+   }
+
+   public void testGetServerDetailsWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/details/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("includestate", "true")
+                       .addFormParam("serverid", "xm3276891").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerApi();
+
+      ServerDetails actual = api.get("xm3276891");
+      assertEquals(actual.toString(), expectedServerDetails().toString());
+   }
+
+   public static ServerDetails expectedServerDetails() {
+      Ip ip = Ip.builder().version4().ip("31.192.231.254").version4().cost(2.0).currency("EUR").build();
+      Cost cost = Cost.builder().amount(10.22).currency("EUR").timePeriod("month").build();
+      return ServerDetails.builder().id("vz1840356").transferGB(50).hostname("glesys-s").cpuCores(1).memorySizeMB(512)
+            .diskSizeGB(5).datacenter("Falkenberg").description("glesys-s-6dd").platform("OpenVZ")
+            .templateName("Ubuntu 10.04 LTS 32-bit").state(Server.State.RUNNING).cost(cost).ips(ip).build();
+   }
+
+   @Test
+   public void testServerDetailsWhenResponseIs4xxReturnsNull() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/details/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("includestate", "true")
+                       .addFormParam("serverid", "xm3276891").build(),
+            HttpResponse.builder().statusCode(404).build()).getServerApi();
+
+      assertNull(api.get("xm3276891"));
+   }
+
+   @Test
+   public void testCreateServerWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/create/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("hostname", "jclouds-test")
+                       .addFormParam("rootpassword", "password")
+                       .addFormParam("datacenter", "Falkenberg")
+                       .addFormParam("platform", "OpenVZ")
+                       .addFormParam("templatename", "Ubuntu 32-bit")
+                       .addFormParam("disksize", "5")
+                       .addFormParam("memorysize", "512")
+                       .addFormParam("cpucores", "1")
+                       .addFormParam("transfer", "50").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_noip.json")).build()).getServerApi();
+
+      Cost cost = Cost.builder().amount(6.38).currency("EUR").timePeriod("month").build();
+      ServerDetails expected = ServerDetails.builder().id("vz1541880").hostname("mammamia").datacenter("Falkenberg").platform("OpenVZ")
+            .templateName("Ubuntu 11.04 64-bit").description("description").cpuCores(1).memorySizeMB(128).diskSizeGB(5).transferGB(50).cost(cost).build();
+
+      assertEquals(
+            api.createWithHostnameAndRootPassword(
+                  ServerSpec.builder().datacenter("Falkenberg").platform("OpenVZ").templateName("Ubuntu 32-bit")
+                        .diskSizeGB(5).memorySizeMB(512).cpuCores(1).transferGB(50).build(), "jclouds-test", "password").toString(),
+            expected.toString());
+   }
+
+   public void testCreateServerWithOptsWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/create/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("hostname", "jclouds-test")
+                       .addFormParam("rootpassword", "password")
+                       .addFormParam("datacenter", "Falkenberg")
+                       .addFormParam("platform", "OpenVZ")
+                       .addFormParam("templatename", "Ubuntu 32-bit")
+                       .addFormParam("disksize", "5")
+                       .addFormParam("memorysize", "512")
+                       .addFormParam("cpucores", "1")
+                       .addFormParam("transfer", "50")
+                       .addFormParam("ip", "10.0.0.1")
+                       .addFormParam("description", "Description-of-server").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerApi();
+
+      CreateServerOptions options = CreateServerOptions.Builder.description("Description-of-server").ip("10.0.0.1");
+
+
+      assertEquals(api.createWithHostnameAndRootPassword(ServerSpec.builder().datacenter("Falkenberg")
+            .platform("OpenVZ").templateName("Ubuntu 32-bit").diskSizeGB(5).memorySizeMB(512).cpuCores(1).transferGB(50)
+            .build(), "jclouds-test", "password", options), expectedServerDetails());
+   }
+
+   @Test
+   public void testUpdateServerWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/edit/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "xm3276891")
+                       .addFormParam("description", "this is a different description!")
+                       .addFormParam("hostname", "new-hostname").build(),
+            HttpResponse.builder().statusCode(206).build()).getServerApi();
+
+      api.update("xm3276891", UpdateServerOptions.Builder.description("this is a different description!").hostname("new-hostname"));
+   }
+
+   @Test
+   public void testUpdateServerWithOptsWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/edit/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "xm3276891")
+                       .addFormParam("description", "Description-of-server")
+                       .addFormParam("disksize", "1")
+                       .addFormParam("memorysize", "512")
+                       .addFormParam("cpucores", "1")
+                       .addFormParam("hostname", "jclouds-test").build(),
+            HttpResponse.builder().statusCode(200).build()).getServerApi();
+
+      UpdateServerOptions options =
+            UpdateServerOptions.Builder.description("Description-of-server").diskSizeGB(1).memorySizeMB(512).cpuCores(1).hostname("jclouds-test");
+
+      api.update("xm3276891", options);
+   }
+
+   @Test
+   public void testCloneServerWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/clone/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "xm3276891")
+                       .addFormParam("hostname", "hostname1").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerApi();
+
+      assertEquals(api.clone("xm3276891", "hostname1"), expectedServerDetails());
+   }
+
+   @Test
+   public void testCloneServerWithOptsWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/clone/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "xm3276891")
+                       .addFormParam("hostname", "hostname1")
+                       .addFormParam("description", "Description-of-server")
+                       .addFormParam("disksize", "1")
+                       .addFormParam("memorysize", "512")
+                       .addFormParam("cpucores", "1").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_details.json")).build()).getServerApi();
+      CloneServerOptions options = (CloneServerOptions) CloneServerOptions.Builder.description("Description-of-server").diskSizeGB(1).memorySizeMB(512).cpuCores(1);
+
+      assertEquals(api.clone("xm3276891", "hostname1", options), expectedServerDetails());
+   }
+
+   @Test(expectedExceptions = {ResourceNotFoundException.class})
+   public void testCloneServerWhenResponseIs4xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/clone/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "xm3276891")
+                       .addFormParam("hostname", "hostname1").build(),
+            HttpResponse.builder().statusCode(404).build()).getServerApi();
+
+      api.clone("xm3276891", "hostname1");
+   }
+
+   public void testGetServerStatusWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/status/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "xm3276891").build(),
+            HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")).build())
+            .getServerApi();
+
+      assertEquals(api.getStatus("xm3276891"), expectedServerStatus());
+   }
+
+   public void testGetServerStatusWithOptsWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/status/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server321")
+                       .addFormParam("statustype", "state").build(),
+            HttpResponse.builder().statusCode(206).payload(payloadFromResource("/server_status.json")).build())
+            .getServerApi();
+
+      assertEquals(api.getStatus("server321", ServerStatusOptions.Builder.state()), expectedServerStatus());
+   }
+
+   public void testGetServerStatusWhenResponseIs4xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/status/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server321")
+                       .addFormParam("statustype", "state").build(),
+            HttpResponse.builder().statusCode(404).build())
+            .getServerApi();
+
+      assertNull(api.getStatus("server321", ServerStatusOptions.Builder.state()));
+   }
+
+   public void testGetServerLimitsWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/limits/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server321").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_limits.json")).build())
+            .getServerApi();
+
+      api.getLimits("server321");
+   }
+
+   public void testGetConsoleWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/console/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server322").build(),
+            HttpResponse.builder().statusCode(200).payload(payloadFromResource("/server_console.json")).build())
+            .getServerApi();
+
+      Console expected = Console.builder().host("79.99.2.147").port(59478).password("1476897311").protocol("vnc").build();
+
+      assertEquals(api.getConsole("server322"), expected);
+   }
+
+   public void testGetConsoleWhenResponseIs4xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/console/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server322").build(),
+            HttpResponse.builder().statusCode(404).build())
+            .getServerApi();
+
+      assertNull(api.getConsole("server322"));
+   }
+
+   public void testStartServerWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/start/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777").build(),
+            HttpResponse.builder().statusCode(200).build())
+            .getServerApi();
+
+      api.start("server777");
+   }
+
+   @Test(expectedExceptions = {AuthorizationException.class})
+   public void testStartServerWhenResponseIs4xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/start/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777").build(),
+            HttpResponse.builder().statusCode(401).build())
+            .getServerApi();
+
+      api.start("server777");
+   }
+
+   public void testStopServerWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/stop/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777").build(),
+            HttpResponse.builder().statusCode(200).build())
+            .getServerApi();
+
+      api.stop("server777");
+   }
+
+   public void testHardStopServerWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/stop/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("type", "hard")
+                       .addFormParam("serverid", "server777").build(),
+            HttpResponse.builder().statusCode(200).build())
+            .getServerApi();
+
+      api.hardStop("server777");
+   }
+
+   @Test(expectedExceptions = {AuthorizationException.class})
+   public void testStopServerWhenResponseIs4xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/stop/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777").build(),
+            HttpResponse.builder().statusCode(401).build())
+            .getServerApi();
+
+      api.stop("server777");
+   }
+
+   public void testRebootServerWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/reboot/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777").build(),
+            HttpResponse.builder().statusCode(200).build())
+            .getServerApi();
+
+      api.reboot("server777");
+   }
+
+   @Test(expectedExceptions = {AuthorizationException.class})
+   public void testRebootServerWhenResponseIs4xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/reboot/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777").build(),
+            HttpResponse.builder().statusCode(401).build())
+            .getServerApi();
+
+      api.reboot("server777");
+   }
+
+   public void testDestroyServerWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/destroy/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777")
+                       .addFormParam("keepip", "true").build(),
+            HttpResponse.builder().statusCode(200).build())
+            .getServerApi();
+
+      api.destroy("server777", DestroyServerOptions.Builder.keepIp());
+   }
+
+   @Test(expectedExceptions = {AuthorizationException.class})
+   public void testDestroyServerWhenResponseIs4xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/destroy/format/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777")
+                       .addFormParam("keepip", "false").build(),
+            HttpResponse.builder().statusCode(401).build())
+            .getServerApi();
+
+      api.destroy("server777", DestroyServerOptions.Builder.discardIp());
+   }
+
+   public void testResourceUsageWhenResponseIs2xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/resourceusage/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777")
+                       .addFormParam("resolution", "minute")
+                       .addFormParam("resource", "diskioread").build(),
+            HttpResponse.builder().statusCode(200)
+                  .payload(payloadFromResourceWithContentType("/server_resource_usage.json", MediaType.APPLICATION_JSON))
+                  .build())
+            .getServerApi();
+
+      ResourceUsage expected = ResourceUsage.builder().info(
+            ResourceUsageInfo.builder().resolution("minute").resource("diskioread").unit("KB").build())
+            .values(
+                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:21:07+02:00")).build(),
+                  ResourceUsageValue.builder().value(5.1).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:22:05+02:00")).build(),
+                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:23:05+02:00")).build(),
+                  ResourceUsageValue.builder().value(10.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:24:08+02:00")).build(),
+                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:25:12+02:00")).build(),
+                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:26:07+02:00")).build(),
+                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:27:12+02:00")).build(),
+                  ResourceUsageValue.builder().value(0.0).timestamp(dateService.iso8601SecondsDateParse("2012-06-24T14:28:05+02:00")).build()
+            ).build();
+      assertEquals(api.getResourceUsage("server777", "diskioread", "minute").toString(), expected.toString());
+   }
+
+   @Test(expectedExceptions = {AuthorizationException.class})
+   public void testResouceUsageWhenResponseIs4xx() throws Exception {
+      ServerApi api = requestSendsResponse(
+            HttpRequest.builder().method("POST").endpoint("https://api.glesys.com/server/resourceusage/format/json")
+                       .addHeader("Accept", "application/json")
+                       .addHeader("Authorization", "Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==")
+                       .addFormParam("serverid", "server777")
+                       .addFormParam("resolution", "minute")
+                       .addFormParam("resource", "diskioread").build(),
+            HttpResponse.builder().statusCode(401).build())
+            .getServerApi();
+
+      api.getResourceUsage("server777", "diskioread", "minute");
+   }
+
+   private ServerStatus expectedServerStatus() {
+      ResourceStatus cpu = ResourceStatus.builder().unit("cores").max(1.0).usage(0.0).build();
+      ResourceStatus disk = ResourceStatus.builder().unit("MB").usage(0.0).max(5120).build();
+      ResourceStatus memory = ResourceStatus.builder().unit("MB").usage(2.0).max(512).build();
+      ServerUptime uptime = ServerUptime.builder().current(21).unit("seconds").build();
+      return ServerStatus.builder().state(Server.State.RUNNING).uptime(uptime).
+            cpu(cpu).disk(disk).memory(memory).build();
+   }
+
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/features/ServerApiLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/features/ServerApiLiveTest.java
new file mode 100644
index 0000000..3de28e4
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/features/ServerApiLiveTest.java
@@ -0,0 +1,303 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.glesys.domain.AllowedArgumentsForCreateServer;
+import org.jclouds.glesys.domain.Console;
+import org.jclouds.glesys.domain.OSTemplate;
+import org.jclouds.glesys.domain.ResourceStatus;
+import org.jclouds.glesys.domain.ResourceUsage;
+import org.jclouds.glesys.domain.Server;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.glesys.domain.ServerLimit;
+import org.jclouds.glesys.domain.ServerStatus;
+import org.jclouds.glesys.internal.BaseGleSYSApiWithAServerLiveTest;
+import org.jclouds.glesys.options.CloneServerOptions;
+import org.jclouds.glesys.options.DestroyServerOptions;
+import org.jclouds.glesys.options.ServerStatusOptions;
+import org.jclouds.glesys.options.UpdateServerOptions;
+import org.jclouds.predicates.RetryablePredicate;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+
+/**
+ * Tests behavior of {@code ServerApi}
+ *
+ * @author Adrian Cole
+ * @author Adam Lowe
+ */
+@Test(groups = "live", testName = "ServerApiLiveTest", singleThreaded = true)
+public class ServerApiLiveTest extends BaseGleSYSApiWithAServerLiveTest {
+   public static final String testHostName2 = "jclouds-test2";
+   
+   @BeforeClass(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      hostName = hostName + "-server";
+      super.setupContext();
+      api = gleContext.getApi().getServerApi();
+   }
+
+   @AfterClass(groups = { "integration", "live" })
+   @Override
+   public void tearDownContext() {
+      if (testServerId2 != null) {
+         api.destroy(testServerId2, DestroyServerOptions.Builder.discardIp());
+      }
+      super.tearDownContext();
+   }
+
+   private ServerApi api;
+   private String testServerId2;
+
+   @BeforeMethod
+   public void makeSureServerIsRunning() throws Exception {
+      serverStatusChecker.apply(Server.State.RUNNING);
+   }
+   
+   @Test
+   public void testAllowedArguments() throws Exception {
+      Map<String,AllowedArgumentsForCreateServer> templates = api.getAllowedArgumentsForCreateByPlatform();
+      
+      assertTrue(templates.containsKey("OpenVZ"));
+      assertTrue(templates.containsKey("Xen"));
+      
+      checkAllowedArguments(templates.get("OpenVZ"));
+      checkAllowedArguments(templates.get("Xen"));
+   }
+
+   private void checkAllowedArguments(AllowedArgumentsForCreateServer t) {
+      assertNotNull(t);
+
+      assert t.getDataCenters().size() > 0 : t;
+      assert t.getCpuCoreOptions().size() > 0 : t;
+      assert t.getDiskSizesInGB().size() > 0 : t;
+      assert t.getMemorySizesInMB().size() > 0 : t;
+      assert t.getTemplateNames().size() > 0 : t;
+      assert t.getTransfersInGB().size() > 0 : t;
+      assert t.getTransfersInGB().size() > 0 : t;
+   }
+   
+   public void testListTemplates() throws Exception {
+      FluentIterable<OSTemplate> oSTemplates = api.listTemplates();
+
+      for(OSTemplate oSTemplate : oSTemplates) {
+         checkTemplate(oSTemplate);
+      }
+   }
+   
+   private void checkTemplate(OSTemplate t) {
+      assertNotNull(t);
+      assertNotNull(t.getName());
+      assertNotNull(t.getOs());
+
+      assertNotNull(t.getPlatform());
+      assert t.getMinDiskSize() > 0 : t;
+      assert t.getMinMemSize() > 0 : t;
+    }
+   
+   public void testListServers() throws Exception {
+      FluentIterable<Server> response = api.list();
+      assertNotNull(response);
+      assertTrue(response.size() > 0);
+
+      for (Server server : response) {
+         ServerDetails newDetails = api.get(server.getId());
+         assertEquals(newDetails.getId(), server.getId());
+         assertEquals(newDetails.getHostname(), server.getHostname());
+         assertEquals(newDetails.getPlatform(), server.getPlatform());
+         assertEquals(newDetails.getDatacenter(), server.getDatacenter());
+         checkServer(newDetails);
+      }
+   }
+
+   public void testServerDetails() throws Exception {
+      ServerDetails details = api.get(serverId);
+      checkServer(details);
+      assertEquals("Ubuntu 10.04 LTS 32-bit", details.getTemplateName());
+      assertEquals("Falkenberg", details.getDatacenter());
+      assertEquals("OpenVZ", details.getPlatform());
+      assertEquals(5, details.getDiskSizeGB());
+      assertEquals(512, details.getMemorySizeMB());
+      assertEquals(1, details.getCpuCores());
+      assertEquals(50, details.getTransferGB());
+   }
+
+   public void testServerStatus() throws Exception {
+      ServerStatus newStatus = api.getStatus(serverId);
+      checkStatus(newStatus);
+   }
+
+   public void testUpdateServer() throws Exception {
+      ServerDetails edited = api.update(serverId, UpdateServerOptions.Builder.description("this is a different description!"));
+      assertEquals(edited.getDescription(), "this is a different description!");
+
+      edited = api.update(serverId, UpdateServerOptions.Builder.description("another description!").hostname("host-name1"));
+      assertEquals(edited.getDescription(), "another description!");
+      assertEquals(edited.getHostname(), "host-name1");
+
+      edited = api.resetPassword(serverId, "anotherpass");
+      assertEquals(edited.getHostname(), "host-name1");
+
+      edited = api.update(serverId, UpdateServerOptions.Builder.hostname(hostName));
+      assertEquals(edited.getHostname(), hostName);
+   }
+
+   @Test
+   public void testRebootServer() throws Exception {
+      assertTrue(serverStatusChecker.apply(Server.State.RUNNING));
+
+      api.reboot(serverId);
+      
+      assertTrue(serverStatusChecker.apply(Server.State.RUNNING));
+   }
+
+   @Test
+   public void testStopAndStartServer() throws Exception {
+      assertTrue(serverStatusChecker.apply(Server.State.RUNNING));
+
+      api.stop(serverId);
+
+      assertTrue(serverStatusChecker.apply(Server.State.STOPPED));
+
+      api.start(serverId);
+
+      assertTrue(serverStatusChecker.apply(Server.State.RUNNING));
+   }
+
+   public void testServerLimits() throws Exception {
+      Map<String, ServerLimit> limits = api.getLimits(serverId);
+      assertNotNull(limits);
+      for (Map.Entry<String, ServerLimit> entry : limits.entrySet()) {
+         assertNotNull(entry.getKey());
+         assertNotNull(entry.getValue());
+         ServerLimit limit = entry.getValue();
+         assertTrue(limit.getBarrier() >= 0);
+         assertTrue(limit.getFailCount() == 0);
+         assertTrue(limit.getHeld() >= 0);
+         assertTrue(limit.getLimit() > 0);
+         assertTrue(limit.getMaxHeld() >= 0);
+      }
+   }
+
+   public void testResourceUsage() throws Exception {
+      // test server has only been in existence for less than a minute - check all servers
+      for (Server server : api.list()) {
+         try {
+            ResourceUsage usage = api.getResourceUsage(server.getId(), "diskioread", "minute");
+            assertEquals(usage.getInfo().getResource(), "diskioread");
+            assertEquals(usage.getInfo().getResolution(), "minute");
+         } catch (UnsupportedOperationException e) {
+
+         }
+         try {
+            ResourceUsage usage = api.getResourceUsage(server.getId(), "cpuusage", "minute");
+            assertEquals(usage.getInfo().getResource(), "cpuusage");
+            assertEquals(usage.getInfo().getResolution(), "minute");
+         } catch (UnsupportedOperationException e) {
+
+         }
+      }
+   }
+
+   public void testConsole() throws Exception {
+      Console console = api.getConsole(serverId);
+      assertNotNull(console);
+      assertNotNull(console.getHost());
+      assertTrue(console.getPort() > 0 && console.getPort() < 65537);
+      assertNotNull(console.getPassword());
+   }
+
+   // takes a few minutes and requires an extra server (used 1 already)
+   @Test(enabled=false)
+   public void testCloneServer() throws Exception {
+      ServerDetails testServer2 = api.clone(serverId, testHostName2, CloneServerOptions.Builder.cpucores(1));
+
+      assertNotNull(testServer2.getId());
+      assertEquals(testServer2.getHostname(), "jclouds-test2");
+      assertTrue(testServer2.getIps().isEmpty());
+      
+      testServerId2 = testServer2.getId();
+
+      RetryablePredicate<Server.State> cloneChecker = new ServerStatusChecker(api, testServerId2, 300, 10, TimeUnit.SECONDS);
+      assertTrue(cloneChecker.apply(Server.State.STOPPED));
+
+      api.start(testServer2.getId());
+
+      // TODO ServerStatus==STOPPED suggests the previous call to start should have worked
+      cloneChecker = new RetryablePredicate<Server.State>(
+            new Predicate<Server.State>() {
+
+               public boolean apply(Server.State value) {
+                  ServerStatus status = api.getStatus(testServerId2, ServerStatusOptions.Builder.state());
+                  if (status.getState() == value) {
+                     return true;
+                  }
+
+                  api.start(testServerId2);
+                  return false;
+               }
+
+            }, 600, 30, TimeUnit.SECONDS);
+
+      assertTrue(cloneChecker.apply(Server.State.RUNNING));
+   }
+
+   private void checkServer(ServerDetails server) {
+      // description can be null
+      assert server.getCpuCores() > 0 : server;
+      assert server.getDiskSizeGB() > 0 : server;
+      assert server.getMemorySizeMB() > 0 : server;
+      assert server.getCost() != null;
+      assert server.getTransferGB() > 0 : server;
+
+      assertNotNull(server.getTemplateName());
+      assertNotNull(server.getIps());
+   }
+
+   private void checkStatus(ServerStatus status) {
+      assertNotNull(status.getState());
+      assertNotNull(status.getUptime());
+
+      
+      for (ResourceStatus usage : new ResourceStatus[] { status.getCpu(), status.getDisk(), status.getMemory() }) {
+         assertNotNull(usage);
+         assert usage.getMax() >= 0.0 : status;
+         assert usage.getUsage() >= 0.0 : status;
+         
+         assertNotNull(usage.getUnit());
+      }
+      
+      assertNotNull(status.getUptime());
+      assert status.getUptime().getCurrent() > 0 : status;
+      assertNotNull(status.getUptime().getUnit());
+   }
+}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiExpectTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiExpectTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiExpectTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiExpectTest.java
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiLiveTest.java
new file mode 100644
index 0000000..83f74fa
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiLiveTest.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.internal;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest;
+import org.jclouds.glesys.GleSYSApi;
+import org.jclouds.glesys.GleSYSAsyncApi;
+import org.jclouds.glesys.features.DomainApi;
+import org.jclouds.predicates.RetryablePredicate;
+import org.jclouds.rest.RestContext;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Tests behavior of {@code GleSYSApi}
+ * 
+ * @author Adrian Cole, Adam Lowe
+ */
+@Test(groups = "live")
+public class BaseGleSYSApiLiveTest extends BaseComputeServiceContextLiveTest {
+   protected String hostName = System.getProperty("user.name").replace('.','-').toLowerCase();
+
+   protected RestContext<GleSYSApi, GleSYSAsyncApi> gleContext;
+
+   public BaseGleSYSApiLiveTest() {
+      provider = "glesys";
+   }
+
+   @BeforeClass(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      super.setupContext();
+      gleContext = view.unwrap();
+   }
+
+   protected void createDomain(String domain) {
+      final DomainApi api = gleContext.getApi().getDomainApi();
+      int before = api.list().size();
+      api.create(domain);
+      RetryablePredicate<Integer> result = new RetryablePredicate<Integer>(new Predicate<Integer>() {
+         public boolean apply(Integer value) {
+            return api.list().size() == value;
+         }
+      }, 30, 1, TimeUnit.SECONDS);
+
+      assertTrue(result.apply(before + 1));
+   }
+
+}
diff --git a/providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiWithAServerLiveTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiWithAServerLiveTest.java
new file mode 100644
index 0000000..a73942e
--- /dev/null
+++ b/providers/glesys/src/test/java/org/jclouds/glesys/internal/BaseGleSYSApiWithAServerLiveTest.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.glesys.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.glesys.domain.Server;
+import org.jclouds.glesys.domain.ServerDetails;
+import org.jclouds.glesys.domain.ServerSpec;
+import org.jclouds.glesys.domain.ServerStatus;
+import org.jclouds.glesys.features.DomainApi;
+import org.jclouds.glesys.features.ServerApi;
+import org.jclouds.glesys.options.DestroyServerOptions;
+import org.jclouds.glesys.options.ServerStatusOptions;
+import org.jclouds.predicates.RetryablePredicate;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicate;
+
+/**
+ * Tests behavior of {@code GleSYSApi}
+ * 
+ * @author Adrian Cole, Adam Lowe
+ */
+@Test(groups = "live", singleThreaded = true)
+public class BaseGleSYSApiWithAServerLiveTest extends BaseGleSYSApiLiveTest {
+   protected String serverId;
+   protected ServerStatusChecker serverStatusChecker;
+
+   public BaseGleSYSApiWithAServerLiveTest() {
+      provider = "glesys";
+   }
+
+   @BeforeClass(groups = { "integration", "live" })
+   @Override
+   public void setupContext() {
+      assertNull(serverId, "This method should be called EXACTLY once per run");
+      super.setupContext();
+      serverStatusChecker = createServer(hostName);
+      serverId = serverStatusChecker.getServerId();
+   }
+
+   @AfterClass(groups = { "integration", "live" })
+   @Override
+   public void tearDownContext() {
+      gleContext.getApi().getServerApi().destroy(serverId, DestroyServerOptions.Builder.discardIp());
+      super.tearDownContext();
+   }
+
+   protected void createDomain(String domain) {
+      final DomainApi api = gleContext.getApi().getDomainApi();
+      int before = api.list().size();
+      api.create(domain);
+      RetryablePredicate<Integer> result = new RetryablePredicate<Integer>(new Predicate<Integer>() {
+         public boolean apply(Integer value) {
+            return api.list().size() == value;
+         }
+      }, 30, 1, TimeUnit.SECONDS);
+
+      assertTrue(result.apply(before + 1));
+   }
+
+   protected ServerStatusChecker createServer(String hostName) {
+      ServerApi api = gleContext.getApi().getServerApi();
+
+      ServerDetails testServer = api.createWithHostnameAndRootPassword(
+            ServerSpec.builder().datacenter("Falkenberg").platform("OpenVZ").templateName("Ubuntu 10.04 LTS 32-bit")
+                  .diskSizeGB(5).memorySizeMB(512).cpuCores(1).transferGB(50).build(), hostName, UUID.randomUUID()
+                  .toString().replace("-",""));
+
+      assertNotNull(testServer.getId());
+      assertEquals(testServer.getHostname(), hostName);
+      assertFalse(testServer.getIps().isEmpty());
+
+      ServerStatusChecker runningServerCounter = new ServerStatusChecker(api, testServer.getId(), 300, 10,
+            TimeUnit.SECONDS);
+
+      assertTrue(runningServerCounter.apply(Server.State.RUNNING));
+      return runningServerCounter;
+   }
+
+   public static class ServerStatusChecker extends RetryablePredicate<Server.State> {
+      private final String serverId;
+
+      public String getServerId() {
+         return serverId;
+      }
+
+      public ServerStatusChecker(final ServerApi api, final String serverId, long maxWait, long period,
+            TimeUnit unit) {
+         super(new Predicate<Server.State>() {
+
+            public boolean apply(Server.State value) {
+               ServerStatus status = api.getStatus(serverId, ServerStatusOptions.Builder.state());
+               return status.getState() == value;
+            }
+
+         }, maxWait, period, unit);
+         this.serverId = serverId;
+      }
+   }
+}
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/parse/ParseFullIpDetailsTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseFullIpDetailsTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/parse/ParseFullIpDetailsTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseFullIpDetailsTest.java
diff --git a/labs/glesys/src/test/java/org/jclouds/glesys/parse/ParseIpAddressFromResponseTest.java b/providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseIpAddressFromResponseTest.java
similarity index 100%
rename from labs/glesys/src/test/java/org/jclouds/glesys/parse/ParseIpAddressFromResponseTest.java
rename to providers/glesys/src/test/java/org/jclouds/glesys/parse/ParseIpAddressFromResponseTest.java
diff --git a/labs/glesys/src/test/resources/archive_allowed_arguments.json b/providers/glesys/src/test/resources/archive_allowed_arguments.json
similarity index 100%
rename from labs/glesys/src/test/resources/archive_allowed_arguments.json
rename to providers/glesys/src/test/resources/archive_allowed_arguments.json
diff --git a/labs/glesys/src/test/resources/archive_details.json b/providers/glesys/src/test/resources/archive_details.json
similarity index 100%
rename from labs/glesys/src/test/resources/archive_details.json
rename to providers/glesys/src/test/resources/archive_details.json
diff --git a/labs/glesys/src/test/resources/archive_list.json b/providers/glesys/src/test/resources/archive_list.json
similarity index 100%
rename from labs/glesys/src/test/resources/archive_list.json
rename to providers/glesys/src/test/resources/archive_list.json
diff --git a/labs/glesys/src/test/resources/domain_details.json b/providers/glesys/src/test/resources/domain_details.json
similarity index 100%
rename from labs/glesys/src/test/resources/domain_details.json
rename to providers/glesys/src/test/resources/domain_details.json
diff --git a/labs/glesys/src/test/resources/domain_list.json b/providers/glesys/src/test/resources/domain_list.json
similarity index 100%
rename from labs/glesys/src/test/resources/domain_list.json
rename to providers/glesys/src/test/resources/domain_list.json
diff --git a/labs/glesys/src/test/resources/domain_list_records.json b/providers/glesys/src/test/resources/domain_list_records.json
similarity index 100%
rename from labs/glesys/src/test/resources/domain_list_records.json
rename to providers/glesys/src/test/resources/domain_list_records.json
diff --git a/labs/glesys/src/test/resources/domain_record.json b/providers/glesys/src/test/resources/domain_record.json
similarity index 100%
rename from labs/glesys/src/test/resources/domain_record.json
rename to providers/glesys/src/test/resources/domain_record.json
diff --git a/labs/glesys/src/test/resources/email_details.json b/providers/glesys/src/test/resources/email_details.json
similarity index 100%
rename from labs/glesys/src/test/resources/email_details.json
rename to providers/glesys/src/test/resources/email_details.json
diff --git a/labs/glesys/src/test/resources/email_list.json b/providers/glesys/src/test/resources/email_list.json
similarity index 100%
rename from labs/glesys/src/test/resources/email_list.json
rename to providers/glesys/src/test/resources/email_list.json
diff --git a/labs/glesys/src/test/resources/email_overview.json b/providers/glesys/src/test/resources/email_overview.json
similarity index 100%
rename from labs/glesys/src/test/resources/email_overview.json
rename to providers/glesys/src/test/resources/email_overview.json
diff --git a/labs/glesys/src/test/resources/ip_get_details.json b/providers/glesys/src/test/resources/ip_get_details.json
similarity index 100%
rename from labs/glesys/src/test/resources/ip_get_details.json
rename to providers/glesys/src/test/resources/ip_get_details.json
diff --git a/labs/glesys/src/test/resources/ip_get_details_xen.json b/providers/glesys/src/test/resources/ip_get_details_xen.json
similarity index 100%
rename from labs/glesys/src/test/resources/ip_get_details_xen.json
rename to providers/glesys/src/test/resources/ip_get_details_xen.json
diff --git a/labs/glesys/src/test/resources/ip_list_free.json b/providers/glesys/src/test/resources/ip_list_free.json
similarity index 100%
rename from labs/glesys/src/test/resources/ip_list_free.json
rename to providers/glesys/src/test/resources/ip_list_free.json
diff --git a/labs/glesys/src/test/resources/ip_list_own.json b/providers/glesys/src/test/resources/ip_list_own.json
similarity index 100%
rename from labs/glesys/src/test/resources/ip_list_own.json
rename to providers/glesys/src/test/resources/ip_list_own.json
diff --git a/labs/glesys/src/test/resources/ip_release.json b/providers/glesys/src/test/resources/ip_release.json
similarity index 100%
rename from labs/glesys/src/test/resources/ip_release.json
rename to providers/glesys/src/test/resources/ip_release.json
diff --git a/labs/glesys/src/test/resources/ip_take.json b/providers/glesys/src/test/resources/ip_take.json
similarity index 100%
rename from labs/glesys/src/test/resources/ip_take.json
rename to providers/glesys/src/test/resources/ip_take.json
diff --git a/labs/glesys/src/test/resources/log4j.xml b/providers/glesys/src/test/resources/log4j.xml
similarity index 100%
rename from labs/glesys/src/test/resources/log4j.xml
rename to providers/glesys/src/test/resources/log4j.xml
diff --git a/labs/glesys/src/test/resources/osmatches.json b/providers/glesys/src/test/resources/osmatches.json
similarity index 100%
rename from labs/glesys/src/test/resources/osmatches.json
rename to providers/glesys/src/test/resources/osmatches.json
diff --git a/labs/glesys/src/test/resources/server_allowed_arguments.json b/providers/glesys/src/test/resources/server_allowed_arguments.json
similarity index 100%
rename from labs/glesys/src/test/resources/server_allowed_arguments.json
rename to providers/glesys/src/test/resources/server_allowed_arguments.json
diff --git a/labs/glesys/src/test/resources/server_console.json b/providers/glesys/src/test/resources/server_console.json
similarity index 100%
rename from labs/glesys/src/test/resources/server_console.json
rename to providers/glesys/src/test/resources/server_console.json
diff --git a/providers/glesys/src/test/resources/server_details.json b/providers/glesys/src/test/resources/server_details.json
new file mode 100644
index 0000000..e2e25c5
--- /dev/null
+++ b/providers/glesys/src/test/resources/server_details.json
@@ -0,0 +1,16 @@
+{"response":{"status":{"code":200,"timestamp":"2012-06-21T14:10:57+02:00","text":"OK"},
+    "server":{
+        "serverid":"vz1840356",
+        "hostname":"glesys-s",
+        "description":"glesys-s-6dd",
+        "cpucores":1,
+        "memorysize":512,
+        "disksize":5,
+        "transfer":50,
+        "templatename":"Ubuntu 10.04 LTS 32-bit",
+        "datacenter":"Falkenberg",
+        "managedhosting":"no",
+        "platform":"OpenVZ",
+        "cost":{"amount":10.22,"currency":"EUR","timeperiod":"month"},
+        "iplist":[{"ipaddress":"31.192.231.254","version":4,"cost":2,"currency":"EUR"}],"state":"running"},
+        "debug":{"input":{"includestate":"1","serverid":"vz1840356"}}}}
\ No newline at end of file
diff --git a/labs/glesys/src/test/resources/server_limits.json b/providers/glesys/src/test/resources/server_limits.json
similarity index 100%
rename from labs/glesys/src/test/resources/server_limits.json
rename to providers/glesys/src/test/resources/server_limits.json
diff --git a/labs/glesys/src/test/resources/server_list.json b/providers/glesys/src/test/resources/server_list.json
similarity index 100%
rename from labs/glesys/src/test/resources/server_list.json
rename to providers/glesys/src/test/resources/server_list.json
diff --git a/labs/glesys/src/test/resources/server_noip.json b/providers/glesys/src/test/resources/server_noip.json
similarity index 100%
rename from labs/glesys/src/test/resources/server_noip.json
rename to providers/glesys/src/test/resources/server_noip.json
diff --git a/labs/glesys/src/test/resources/server_resource_usage.json b/providers/glesys/src/test/resources/server_resource_usage.json
similarity index 100%
rename from labs/glesys/src/test/resources/server_resource_usage.json
rename to providers/glesys/src/test/resources/server_resource_usage.json
diff --git a/labs/glesys/src/test/resources/server_status.json b/providers/glesys/src/test/resources/server_status.json
similarity index 100%
rename from labs/glesys/src/test/resources/server_status.json
rename to providers/glesys/src/test/resources/server_status.json
diff --git a/labs/glesys/src/test/resources/server_templates.json b/providers/glesys/src/test/resources/server_templates.json
similarity index 100%
rename from labs/glesys/src/test/resources/server_templates.json
rename to providers/glesys/src/test/resources/server_templates.json
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageApi.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageApi.java
new file mode 100644
index 0000000..80395a1
--- /dev/null
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageApi.java
@@ -0,0 +1,62 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.hpcloud.objectstorage;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerApi;
+import org.jclouds.location.Region;
+import org.jclouds.openstack.swift.CommonSwiftClient;
+import org.jclouds.rest.annotations.Delegate;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.inject.Provides;
+
+/**
+ * Provides synchronous access to HP Cloud Object Storage via the REST API.
+ * 
+ * <p/>
+ * All commands return a ListenableFuture of the result. Any exceptions incurred during processing
+ * will be backend in an {@link java.util.concurrent.ExecutionException} as documented in
+ * {@link ListenableFuture#get()}.
+ * 
+ * @see HPCloudObjectStorageAsyncApi
+ * @see <a href="https://manage.hpcloud.com/pages/build/docs/objectstorage-lvs/api">HP Cloud Object
+ *      Storage API</a>
+ * @author Jeremy Daggett
+ */
+@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
+public interface HPCloudObjectStorageApi extends CommonSwiftClient {
+   /**
+    * 
+    * @return the Region codes configured
+    */
+   @Provides
+   @Region
+   Set<String> getConfiguredRegions();
+
+   /**
+    * Provides synchronous access to CDN features.
+    */
+   @Delegate
+   Optional<CDNContainerApi> getCDNExtension();
+}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageApiMetadata.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageApiMetadata.java
index 522bd4c..4586f48 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageApiMetadata.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageApiMetadata.java
@@ -42,7 +42,7 @@
    /** The serialVersionUID */
    private static final long serialVersionUID = 820062881469203616L;
    
-   public static final TypeToken<RestContext<HPCloudObjectStorageClient, HPCloudObjectStorageAsyncClient>> CONTEXT_TOKEN = new TypeToken<RestContext<HPCloudObjectStorageClient, HPCloudObjectStorageAsyncClient>>() {
+   public static final TypeToken<RestContext<HPCloudObjectStorageApi, HPCloudObjectStorageAsyncApi>> CONTEXT_TOKEN = new TypeToken<RestContext<HPCloudObjectStorageApi, HPCloudObjectStorageAsyncApi>>() {
       private static final long serialVersionUID = -5070937833892503232L;
    };
 
@@ -70,7 +70,7 @@
 
    public static class Builder extends SwiftKeystoneApiMetadata.Builder {
       protected Builder(){
-         super(HPCloudObjectStorageClient.class, HPCloudObjectStorageAsyncClient.class);
+         super(HPCloudObjectStorageApi.class, HPCloudObjectStorageAsyncApi.class);
          id("hpcloud-objectstorage")
          .endpointName("identity service url ending in /v2.0/")
          .defaultEndpoint("https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/")
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageAsyncApi.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageAsyncApi.java
new file mode 100644
index 0000000..19b6475
--- /dev/null
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageAsyncApi.java
@@ -0,0 +1,97 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.hpcloud.objectstorage;
+
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerAsyncApi;
+import org.jclouds.location.Region;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
+import org.jclouds.openstack.swift.Storage;
+import org.jclouds.openstack.swift.domain.ContainerMetadata;
+import org.jclouds.openstack.swift.functions.ReturnTrueOn404FalseOn409;
+import org.jclouds.openstack.swift.options.ListContainerOptions;
+import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.Endpoint;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SkipEncoding;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.inject.Provides;
+
+/**
+ * Provides asynchronous access to HP Cloud Object Storage via the REST API.
+ * 
+ * <p/>
+ * All commands return a ListenableFuture of the result. Any exceptions incurred during processing
+ * will be backend in an {@link java.util.concurrent.ExecutionException} as documented in
+ * {@link ListenableFuture#get()}.
+ * 
+ * @see HPCloudObjectStorageApi
+ * @see <a href="https://manage.hpcloud.com/pages/build/docs/objectstorage-lvs/api">HP Cloud Object
+ *      Storage API</a>
+ * @author Jeremy Daggett
+ */
+@SkipEncoding('/')
+@RequestFilters(AuthenticateRequest.class)
+@Endpoint(Storage.class)
+public interface HPCloudObjectStorageAsyncApi extends CommonSwiftAsyncClient {
+   /**
+    * 
+    * @return the Region codes configured
+    */
+   @Provides
+   @Region
+   Set<String> getConfiguredRegions();
+
+   /**
+    * @see org.jclouds.openstack.swift.CommonSwiftClient#listContainers
+    */
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @QueryParams(keys = "format", values = "json")
+   @Path("/")
+   ListenableFuture<? extends Set<ContainerMetadata>> listContainers(ListContainerOptions... options);
+
+   /**
+    * @see org.jclouds.openstack.swift.CommonSwiftClient#deleteContainerIfEmpty
+    */
+   @DELETE
+   @ExceptionParser(ReturnTrueOn404FalseOn409.class)
+   @Path("/{container}")
+   ListenableFuture<Boolean> deleteContainerIfEmpty(@PathParam("container") String container);
+
+   /**
+    * Provides asynchronous access to CDN features.
+    */
+   @Delegate
+   Optional<CDNContainerAsyncApi> getCDNExtension();
+
+}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageAsyncClient.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageAsyncClient.java
deleted file mode 100644
index ae49064..0000000
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageAsyncClient.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.hpcloud.objectstorage;
-
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.hpcloud.objectstorage.extensions.HPCloudCDNAsyncClient;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
-import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
-import org.jclouds.openstack.swift.Storage;
-import org.jclouds.openstack.swift.domain.ContainerMetadata;
-import org.jclouds.openstack.swift.functions.ReturnTrueOn404FalseOn409;
-import org.jclouds.openstack.swift.options.ListContainerOptions;
-import org.jclouds.rest.annotations.Delegate;
-import org.jclouds.rest.annotations.Endpoint;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.QueryParams;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.SkipEncoding;
-
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides asynchronous access to HP Cloud Object Storage via the REST API.
- * 
- * <p/>
- * All commands return a ListenableFuture of the result. Any exceptions incurred during processing
- * will be backend in an {@link java.util.concurrent.ExecutionException} as documented in
- * {@link ListenableFuture#get()}.
- * 
- * @see HPCloudObjectStorageClient
- * @see <a href="https://manage.hpcloud.com/pages/build/docs/objectstorage-lvs/api">HP Cloud Object
- *      Storage API</a>
- * @author Jeremy Daggett
- */
-@SkipEncoding('/')
-@RequestFilters(AuthenticateRequest.class)
-@Endpoint(Storage.class)
-public interface HPCloudObjectStorageAsyncClient extends CommonSwiftAsyncClient {
-
-   /**
-    * @see org.jclouds.openstack.swift.CommonSwiftClient#listContainers
-    */
-   @GET
-   @Consumes(MediaType.APPLICATION_JSON)
-   @QueryParams(keys = "format", values = "json")
-   @Path("/")
-   ListenableFuture<? extends Set<ContainerMetadata>> listContainers(ListContainerOptions... options);
-
-   /**
-    * @see org.jclouds.openstack.swift.CommonSwiftClient#deleteContainerIfEmpty
-    */
-   @DELETE
-   @ExceptionParser(ReturnTrueOn404FalseOn409.class)
-   @Path("/{container}")
-   ListenableFuture<Boolean> deleteContainerIfEmpty(@PathParam("container") String container);
-
-   /**
-    * Provides synchronous access to CDN features.
-    */
-   @Delegate
-   Optional<HPCloudCDNAsyncClient> getCDNExtension();
-
-}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageClient.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageClient.java
deleted file mode 100644
index 92dc16c..0000000
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageClient.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.hpcloud.objectstorage;
-
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.hpcloud.objectstorage.extensions.HPCloudCDNClient;
-import org.jclouds.openstack.swift.CommonSwiftClient;
-import org.jclouds.rest.annotations.Delegate;
-
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides synchronous access to HP Cloud Object Storage via the REST API.
- * 
- * <p/>
- * All commands return a ListenableFuture of the result. Any exceptions incurred during processing
- * will be backend in an {@link java.util.concurrent.ExecutionException} as documented in
- * {@link ListenableFuture#get()}.
- * 
- * @see org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageClient
- * @see <a href="https://manage.hpcloud.com/pages/build/docs/objectstorage-lvs/api">HP Cloud Object
- *      Storage API</a>
- * @author Jeremy Daggett
- */
-@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
-public interface HPCloudObjectStorageClient extends CommonSwiftClient {
-
-   /**
-    * Provides synchronous access to CDN features.
-    */
-   @Delegate
-   Optional<HPCloudCDNClient> getCDNExtension();
-}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageProviderMetadata.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageProviderMetadata.java
index 8a8262c..f893000 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageProviderMetadata.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageProviderMetadata.java
@@ -18,8 +18,6 @@
  */
 package org.jclouds.hpcloud.objectstorage;
 
-import static org.jclouds.openstack.keystone.v2_0.config.CredentialTypes.API_ACCESS_KEY_CREDENTIALS;
-import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.CREDENTIAL_TYPE;
 import static org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties.REQUIRES_TENANT;
 
 import java.net.URI;
@@ -57,7 +55,6 @@
 
    public static Properties defaultProperties() {
       Properties properties = new Properties();
-      properties.setProperty(CREDENTIAL_TYPE, API_ACCESS_KEY_CREDENTIALS);
       properties.setProperty(REQUIRES_TENANT, "true");
       return properties;
    }
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageAsyncBlobStore.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageAsyncBlobStore.java
index 847eb68..15f95a0 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageAsyncBlobStore.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageAsyncBlobStore.java
@@ -35,8 +35,8 @@
 import org.jclouds.collect.Memoized;
 import org.jclouds.concurrent.Futures;
 import org.jclouds.domain.Location;
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncClient;
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageClient;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncApi;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
 import org.jclouds.hpcloud.objectstorage.blobstore.functions.EnableCDNAndCache;
 import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore;
 import org.jclouds.openstack.swift.blobstore.functions.BlobStoreListContainerOptionsToListContainerOptions;
@@ -57,22 +57,22 @@
  */
 @Singleton
 public class HPCloudObjectStorageAsyncBlobStore extends SwiftAsyncBlobStore {
-   private final EnableCDNAndCache enableCDNAndCache;
+   private final EnableCDNAndCache enableAndCache;
 
    @Inject
    protected HPCloudObjectStorageAsyncBlobStore(BlobStoreContext context, BlobUtils blobUtils,
             @Named(Constants.PROPERTY_USER_THREADS) ExecutorService service, Supplier<Location> defaultLocation,
-            @Memoized Supplier<Set<? extends Location>> locations, HPCloudObjectStorageClient sync, HPCloudObjectStorageAsyncClient async,
+            @Memoized Supplier<Set<? extends Location>> locations, HPCloudObjectStorageApi sync, HPCloudObjectStorageAsyncApi async,
             ContainerToResourceMetadata container2ResourceMd,
             BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
             ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
             ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
-            Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableCDNAndCache,
+            Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableAndCache,
             Provider<AsyncMultipartUploadStrategy> multipartUploadStrategy) {
       super(context, blobUtils, service, defaultLocation, locations, sync, async, container2ResourceMd,
                container2ContainerListOptions, container2ResourceList, object2Blob, blob2Object, object2BlobMd,
                blob2ObjectGetOptions, fetchBlobMetadataProvider, multipartUploadStrategy);
-      this.enableCDNAndCache = enableCDNAndCache;
+      this.enableAndCache = enableAndCache;
    }
 
    @Override
@@ -86,7 +86,7 @@
             @Override
             public Boolean apply(Boolean input) {
                if (Boolean.TRUE.equals(input)) {
-                  return enableCDNAndCache.apply(container) != null;
+                  return enableAndCache.apply(container) != null;
                }
                return false;
             }
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobRequestSigner.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobRequestSigner.java
index 90829b5..b2f6ffa 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobRequestSigner.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobRequestSigner.java
@@ -11,7 +11,7 @@
 import org.jclouds.blobstore.BlobRequestSigner;
 import org.jclouds.blobstore.domain.Blob;
 import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncClient;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncApi;
 import org.jclouds.http.HttpRequest;
 import org.jclouds.http.options.GetOptions;
 import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
@@ -19,12 +19,11 @@
 import org.jclouds.rest.internal.RestAnnotationProcessor;
 
 /**
- * 
  * @author Adrian Cole
  */
 @Singleton
 public class HPCloudObjectStorageBlobRequestSigner implements BlobRequestSigner {
-   private final RestAnnotationProcessor<HPCloudObjectStorageAsyncClient> processor;
+   private final RestAnnotationProcessor<HPCloudObjectStorageAsyncApi> processor;
    private final BlobToObject blobToObject;
    private final BlobToHttpGetOptions blob2HttpGetOptions;
 
@@ -33,16 +32,15 @@
    private final Method createMethod;
 
    @Inject
-   public HPCloudObjectStorageBlobRequestSigner(RestAnnotationProcessor<HPCloudObjectStorageAsyncClient> processor, BlobToObject blobToObject,
+   public HPCloudObjectStorageBlobRequestSigner(RestAnnotationProcessor<HPCloudObjectStorageAsyncApi> processor, BlobToObject blobToObject,
             BlobToHttpGetOptions blob2HttpGetOptions) throws SecurityException, NoSuchMethodException {
       this.processor = checkNotNull(processor, "processor");
       this.blobToObject = checkNotNull(blobToObject, "blobToObject");
       this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions");
-      this.getMethod = HPCloudObjectStorageAsyncClient.class.getMethod("getObject", String.class, String.class,
+      this.getMethod = HPCloudObjectStorageAsyncApi.class.getMethod("getObject", String.class, String.class,
                GetOptions[].class);
-      this.deleteMethod = HPCloudObjectStorageAsyncClient.class.getMethod("removeObject", String.class, String.class);
-      this.createMethod = HPCloudObjectStorageAsyncClient.class.getMethod("putObject", String.class, SwiftObject.class);
-
+      this.deleteMethod = HPCloudObjectStorageAsyncApi.class.getMethod("removeObject", String.class, String.class);
+      this.createMethod = HPCloudObjectStorageAsyncApi.class.getMethod("putObject", String.class, SwiftObject.class);
    }
 
    @Override
@@ -51,11 +49,21 @@
    }
 
    @Override
+   public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signPutBlob(String container, Blob blob) {
       return cleanRequest(processor.createRequest(createMethod, container, blobToObject.apply(blob)));
    }
 
    @Override
+   public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
    public HttpRequest signRemoveBlob(String container, String name) {
       return cleanRequest(processor.createRequest(deleteMethod, container, name));
    }
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java
index 365cb29..eeb058c 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStore.java
@@ -31,7 +31,7 @@
 import org.jclouds.blobstore.util.BlobUtils;
 import org.jclouds.collect.Memoized;
 import org.jclouds.domain.Location;
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageClient;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
 import org.jclouds.hpcloud.objectstorage.blobstore.functions.EnableCDNAndCache;
 import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
 import org.jclouds.openstack.swift.blobstore.functions.BlobStoreListContainerOptionsToListContainerOptions;
@@ -51,21 +51,21 @@
 @Singleton
 public class HPCloudObjectStorageBlobStore extends SwiftBlobStore {
 
-   private EnableCDNAndCache enableCDNAndCache;
+   private EnableCDNAndCache enableAndCache;
 
    @Inject
    protected HPCloudObjectStorageBlobStore(BlobStoreContext context, BlobUtils blobUtils,
             Supplier<Location> defaultLocation, @Memoized Supplier<Set<? extends Location>> locations,
-            HPCloudObjectStorageClient sync, ContainerToResourceMetadata container2ResourceMd,
+            HPCloudObjectStorageApi sync, ContainerToResourceMetadata container2ResourceMd,
             BlobStoreListContainerOptionsToListContainerOptions container2ContainerListOptions,
             ContainerToResourceList container2ResourceList, ObjectToBlob object2Blob, BlobToObject blob2Object,
             ObjectToBlobMetadata object2BlobMd, BlobToHttpGetOptions blob2ObjectGetOptions,
-            Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableCDNAndCache,
+            Provider<FetchBlobMetadata> fetchBlobMetadataProvider, EnableCDNAndCache enableAndCache,
             Provider<MultipartUploadStrategy> multipartUploadStrategy) {
       super(context, blobUtils, defaultLocation, locations, sync, container2ResourceMd, container2ContainerListOptions,
                container2ResourceList, object2Blob, blob2Object, object2BlobMd, blob2ObjectGetOptions,
                fetchBlobMetadataProvider, multipartUploadStrategy);
-      this.enableCDNAndCache = enableCDNAndCache;
+      this.enableAndCache = enableAndCache;
 
    }
 
@@ -75,7 +75,7 @@
          return createContainerInLocation(location, container);
       } finally {
          if (options.isPublicRead())
-            enableCDNAndCache.apply(container);
+            enableAndCache.apply(container);
       }
    }
 
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java
index bfc73bd..5b91f49 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/config/HPCloudObjectStorageBlobStoreContextModule.java
@@ -33,13 +33,13 @@
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.attr.ConsistencyModel;
 import org.jclouds.blobstore.config.BlobStoreMapModule;
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageClient;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
 import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageAsyncBlobStore;
 import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageBlobRequestSigner;
 import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageBlobStore;
 import org.jclouds.hpcloud.objectstorage.blobstore.functions.HPCloudObjectStorageObjectToBlobMetadata;
-import org.jclouds.hpcloud.objectstorage.domain.ContainerCDNMetadata;
-import org.jclouds.hpcloud.objectstorage.extensions.HPCloudCDNClient;
+import org.jclouds.hpcloud.objectstorage.domain.CDNContainer;
+import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerApi;
 import org.jclouds.http.HttpResponseException;
 import org.jclouds.logging.Logger;
 import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
@@ -64,19 +64,19 @@
      @Resource
      protected Logger logger = Logger.NULL;
 
-     private final HPCloudObjectStorageClient client;
+     private final HPCloudObjectStorageApi client;
 
       @Inject
-      public GetCDNMetadata(HPCloudObjectStorageClient client) {
+      public GetCDNMetadata(HPCloudObjectStorageApi client) {
          this.client = client;
       }
 
       @Override
       public URI load(String container) {
-         Optional<HPCloudCDNClient> cdnExtension = client.getCDNExtension();
+         Optional<CDNContainerApi> cdnExtension = client.getCDNExtension();
          checkArgument(cdnExtension.isPresent(), "CDN is required, but the extension is not available!");
          try {
-            ContainerCDNMetadata md = cdnExtension.get().getCDNMetadata(container);
+            CDNContainer md = cdnExtension.get().get(container);
             return md != null ? md.getCDNUri() : null;
          } catch (HttpResponseException e) {
             // TODO: this is due to beta status
@@ -90,7 +90,7 @@
 
       @Override
       public String toString() {
-         return "getCDNMetadata()";
+         return "get()";
       }
    }
 
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/functions/EnableCDNAndCache.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/functions/EnableCDNAndCache.java
index c24d3f4..74c7585 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/functions/EnableCDNAndCache.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/blobstore/functions/EnableCDNAndCache.java
@@ -25,8 +25,8 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageClient;
-import org.jclouds.hpcloud.objectstorage.extensions.HPCloudCDNClient;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
+import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerApi;
 
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
@@ -39,19 +39,19 @@
 @Singleton
 public class EnableCDNAndCache implements Function<String, URI> {
    private final LoadingCache<String, URI> cdnContainer;
-   private final HPCloudObjectStorageClient sync;
+   private final HPCloudObjectStorageApi sync;
 
    @Inject
-   public EnableCDNAndCache(HPCloudObjectStorageClient sync, LoadingCache<String, URI> cdnContainer) {
+   public EnableCDNAndCache(HPCloudObjectStorageApi sync, LoadingCache<String, URI> cdnContainer) {
       this.sync = sync;
       this.cdnContainer = cdnContainer;
    }
 
    @Override
    public URI apply(String input) {
-      Optional<HPCloudCDNClient> cdnExtension = sync.getCDNExtension();
+      Optional<CDNContainerApi> cdnExtension = sync.getCDNExtension();
       checkArgument(cdnExtension.isPresent(), "CDN is required, but the extension is not available!");
-      URI uri = cdnExtension.get().enableCDN(input);
+      URI uri = cdnExtension.get().enable(input);
       cdnContainer.put(input, uri);
       return uri;
    }
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/config/HPCloudObjectStorageRestClientModule.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/config/HPCloudObjectStorageRestClientModule.java
index 38fc722..dc28e2f 100644
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/config/HPCloudObjectStorageRestClientModule.java
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/config/HPCloudObjectStorageRestClientModule.java
@@ -25,10 +25,10 @@
 
 import javax.inject.Singleton;
 
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncClient;
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageClient;
-import org.jclouds.hpcloud.objectstorage.extensions.HPCloudCDNAsyncClient;
-import org.jclouds.hpcloud.objectstorage.extensions.HPCloudCDNClient;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncApi;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
+import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerAsyncApi;
+import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerApi;
 import org.jclouds.hpcloud.services.HPExtensionCDN;
 import org.jclouds.hpcloud.services.HPExtensionServiceType;
 import org.jclouds.location.suppliers.RegionIdToURISupplier;
@@ -50,18 +50,18 @@
  */
 @ConfiguresRestClient
 public class HPCloudObjectStorageRestClientModule extends
-         SwiftRestClientModule<HPCloudObjectStorageClient, HPCloudObjectStorageAsyncClient> {
+         SwiftRestClientModule<HPCloudObjectStorageApi, HPCloudObjectStorageAsyncApi> {
    public static final Map<Class<?>, Class<?>> DELEGATE_MAP = ImmutableMap.<Class<?>, Class<?>> builder().put(
-            HPCloudCDNClient.class, HPCloudCDNAsyncClient.class).build();
+            CDNContainerApi.class, CDNContainerAsyncApi.class).build();
 
    public HPCloudObjectStorageRestClientModule() {
-      super(TypeToken.of(HPCloudObjectStorageClient.class), TypeToken.of(HPCloudObjectStorageAsyncClient.class),
+      super(TypeToken.of(HPCloudObjectStorageApi.class), TypeToken.of(HPCloudObjectStorageAsyncApi.class),
                DELEGATE_MAP);
    }
 
    protected void bindResolvedClientsToCommonSwift() {
-      bind(CommonSwiftClient.class).to(HPCloudObjectStorageClient.class).in(Scopes.SINGLETON);
-      bind(CommonSwiftAsyncClient.class).to(HPCloudObjectStorageAsyncClient.class).in(Scopes.SINGLETON);
+      bind(CommonSwiftClient.class).to(HPCloudObjectStorageApi.class).in(Scopes.SINGLETON);
+      bind(CommonSwiftAsyncClient.class).to(HPCloudObjectStorageAsyncApi.class).in(Scopes.SINGLETON);
    }
    
    @Provides
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/domain/CDNContainer.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/domain/CDNContainer.java
new file mode 100644
index 0000000..832b276
--- /dev/null
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/domain/CDNContainer.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.hpcloud.objectstorage.domain;
+
+import java.beans.ConstructorProperties;
+import java.net.URI;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
+import com.google.common.base.Objects.ToStringHelper;
+
+public class CDNContainer implements Comparable<CDNContainer> {
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromCDNContainer(this);
+   }
+
+   public static class Builder {
+
+      protected String name;
+      protected boolean cdnEnabled;
+      protected long ttl;
+      protected URI CDNUri;
+      protected String referrerAcl;
+      protected String useragentAcl;
+      protected boolean logRetention;
+
+      /**
+       * @see CDNContainer#getName()
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /**
+       * @see CDNContainer#isCDNEnabled()
+       */
+      public Builder CDNEnabled(boolean cdnEnabled) {
+         this.cdnEnabled = cdnEnabled;
+         return this;
+      }
+
+      /**
+       * @see CDNContainer#getTTL
+       */
+      public Builder ttl(long ttl) {
+         this.ttl = ttl;
+         return this;
+      }
+
+      /**
+       * @see CDNContainer#getCDNUri()
+       */
+      public Builder CDNUri(URI CDNUri) {
+         this.CDNUri = CDNUri;
+         return this;
+      }
+
+      /**
+       * @see CDNContainer#getReferrerAcl()
+       */
+      public Builder referrerAcl(String referrerAcl) {
+         this.referrerAcl = referrerAcl;
+         return this;
+      }
+
+      /**
+       * @see CDNContainer#getUseragentAcl()
+       */
+      public Builder useragent_acl(String useragentAcl) {
+         this.useragentAcl = useragentAcl;
+         return this;
+      }
+
+      /**
+       * @see CDNContainer#isLogRetention()
+       */
+      public Builder logRetention(boolean logRetention) {
+         this.logRetention = logRetention;
+         return this;
+      }
+
+      public CDNContainer build() {
+         return new CDNContainer(name, cdnEnabled, ttl, CDNUri, referrerAcl, useragentAcl, logRetention);
+      }
+
+      public Builder fromCDNContainer(CDNContainer in) {
+         return this.name(in.getName()).CDNEnabled(in.isCDNEnabled()).ttl(in.getTTL()).CDNUri(in.getCDNUri())
+                  .referrerAcl(in.getReferrerAcl()).useragent_acl(in.getUseragentAcl())
+                  .logRetention(in.isLogRetention());
+      }
+   }
+
+   private final String name;
+   private final boolean cdnEnabled;
+   private final long ttl;
+   private final URI CDNUri;
+   private final String referrerAcl;
+   private final String useragentAcl;
+   private final boolean logRetention;
+
+   @ConstructorProperties({ "name", "cdn_enabled", "ttl", "cdn_uri", "referrer_acl", "useragent_acl", "log_retention" })
+   protected CDNContainer(@Nullable String name, boolean cdnEnabled, long ttl, @Nullable URI CDNUri,
+            @Nullable String referrerAcl, @Nullable String useragentAcl, boolean logRetention) {
+      this.name = Strings.emptyToNull(name);
+      this.cdnEnabled = cdnEnabled;
+      this.ttl = ttl;
+      this.CDNUri = CDNUri;
+      this.referrerAcl = Strings.emptyToNull(referrerAcl);
+      this.useragentAcl = Strings.emptyToNull(useragentAcl);
+      this.logRetention = logRetention;
+   }
+
+   /**
+    * Beware: The container name is not available from HEAD CDN responses and will be null.
+    * 
+    * @return the name of the container to which these CDN settings apply.
+    */
+   @Nullable
+   public String getName() {
+      return this.name;
+   }
+
+   public boolean isCDNEnabled() {
+      return this.cdnEnabled;
+   }
+
+   public long getTTL() {
+      return this.ttl;
+   }
+
+   @Nullable
+   public URI getCDNUri() {
+      return this.CDNUri;
+   }
+
+   @Nullable
+   public String getReferrerAcl() {
+      return this.referrerAcl;
+   }
+
+   @Nullable
+   public String getUseragentAcl() {
+      return this.useragentAcl;
+   }
+
+   public boolean isLogRetention() {
+      return this.logRetention;
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(name, CDNUri);
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null || getClass() != obj.getClass())
+         return false;
+      CDNContainer that = CDNContainer.class.cast(obj);
+      return Objects.equal(this.name, that.name) && Objects.equal(this.CDNUri, that.CDNUri);
+   }
+
+   protected ToStringHelper string() {
+      return Objects.toStringHelper(this).omitNullValues().add("name", name).add("cdnEnabled", cdnEnabled)
+               .add("ttl", ttl).add("CDNUri", CDNUri).add("referrerAcl", referrerAcl).add("useragentAcl", useragentAcl)
+               .add("logRetention", logRetention);
+   }
+
+   @Override
+   public String toString() {
+      return string().toString();
+   }
+
+   public int compareTo(CDNContainer o) {
+      if (getName() == null)
+         return -1;
+      return (this == o) ? 0 : getName().compareTo(o.getName());
+   }
+}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/domain/ContainerCDNMetadata.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/domain/ContainerCDNMetadata.java
deleted file mode 100644
index b931ded..0000000
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/domain/ContainerCDNMetadata.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.hpcloud.objectstorage.domain;
-
-import java.beans.ConstructorProperties;
-import java.net.URI;
-
-import org.jclouds.javax.annotation.Nullable;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * @author James Murty
- */
-public class ContainerCDNMetadata implements Comparable<ContainerCDNMetadata> {
-
-   public static Builder<?> builder() {
-      return new ConcreteBuilder();
-   }
-
-   public Builder<?> toBuilder() {
-      return new ConcreteBuilder().fromContainerCDNMetadata(this);
-   }
-
-   public static abstract class Builder<T extends Builder<T>> {
-      protected abstract T self();
-
-      protected String name;
-      protected boolean cdnEnabled;
-      protected long ttl;
-      protected URI CDNUri;
-      protected String referrerAcl;
-      protected String useragentAcl;
-      protected boolean logRetention;
-
-      /**
-       * @see ContainerCDNMetadata#getName()
-       */
-      public T name(String name) {
-         this.name = name;
-         return self();
-      }
-
-      /**
-       * @see ContainerCDNMetadata#isCDNEnabled()
-       */
-      public T CDNEnabled(boolean cdnEnabled) {
-         this.cdnEnabled = cdnEnabled;
-         return self();
-      }
-
-      /**
-       * @see ContainerCDNMetadata#getTTL
-       */
-      public T ttl(long ttl) {
-         this.ttl = ttl;
-         return self();
-      }
-
-      /**
-       * @see ContainerCDNMetadata#getCDNUri()
-       */
-      public T CDNUri(URI CDNUri) {
-         this.CDNUri = CDNUri;
-         return self();
-      }
-
-      /**
-       * @see ContainerCDNMetadata#getReferrerAcl()
-       */
-      public T referrerAcl(String referrerAcl) {
-         this.referrerAcl = referrerAcl;
-         return self();
-      }
-
-      /**
-       * @see ContainerCDNMetadata#getUseragentAcl()
-       */
-      public T useragent_acl(String useragentAcl) {
-         this.useragentAcl = useragentAcl;
-         return self();
-      }
-
-      /**
-       * @see ContainerCDNMetadata#isLogRetention()
-       */
-      public T logRetention(boolean logRetention) {
-         this.logRetention = logRetention;
-         return self();
-      }
-
-      public ContainerCDNMetadata build() {
-         return new ContainerCDNMetadata(name, cdnEnabled, ttl, CDNUri, referrerAcl, useragentAcl, logRetention);
-      }
-
-      public T fromContainerCDNMetadata(ContainerCDNMetadata in) {
-         return this
-               .name(in.getName())
-               .CDNEnabled(in.isCDNEnabled())
-               .ttl(in.getTTL())
-               .CDNUri(in.getCDNUri())
-               .referrerAcl(in.getReferrerAcl())
-               .useragent_acl(in.getUseragentAcl())
-               .logRetention(in.isLogRetention());
-      }
-   }
-
-   private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
-      @Override
-      protected ConcreteBuilder self() {
-         return this;
-      }
-   }
-
-   private final String name;
-   private final boolean cdnEnabled;
-   private final long ttl;
-   private final URI CDNUri;
-   private final String referrerAcl;
-   private final String useragentAcl;
-   private final boolean logRetention;
-
-   @ConstructorProperties({
-         "name", "cdn_enabled", "ttl", "x-cdn-uri", "referrer_acl", "useragent_acl", "log_retention"
-   })
-   protected ContainerCDNMetadata(@Nullable String name, boolean cdnEnabled, long ttl, @Nullable URI CDNUri,
-                                  @Nullable String referrerAcl, @Nullable String useragentAcl, boolean logRetention) {
-      this.name = name;
-      this.cdnEnabled = cdnEnabled;
-      this.ttl = ttl;
-      this.CDNUri = CDNUri;
-      this.referrerAcl = referrerAcl;
-      this.useragentAcl = useragentAcl;
-      this.logRetention = logRetention;
-   }
-
-   /**
-    * Beware: The container name is not available from HEAD CDN responses and will be null.
-    *
-    * @return the name of the container to which these CDN settings apply.
-    */
-   @Nullable
-   public String getName() {
-      return this.name;
-   }
-
-   public boolean isCDNEnabled() {
-      return this.cdnEnabled;
-   }
-
-   public long getTTL() {
-      return this.ttl;
-   }
-
-   @Nullable
-   public URI getCDNUri() {
-      return this.CDNUri;
-   }
-
-   @Nullable
-   public String getReferrerAcl() {
-      return this.referrerAcl;
-   }
-
-   @Nullable
-   public String getUseragentAcl() {
-      return this.useragentAcl;
-   }
-
-   public boolean isLogRetention() {
-      return this.logRetention;
-   }
-
-   @Override
-   public int hashCode() {
-      return Objects.hashCode(name, CDNUri);
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (obj == null || getClass() != obj.getClass()) return false;
-      ContainerCDNMetadata that = ContainerCDNMetadata.class.cast(obj);
-      return Objects.equal(this.name, that.name) && Objects.equal(this.CDNUri, that.CDNUri);
-   }
-
-   protected ToStringHelper string() {
-      return Objects.toStringHelper(this)
-            .add("name", name).add("cdnEnabled", cdnEnabled).add("ttl", ttl).add("CDNUri", CDNUri)
-            .add("referrerAcl", referrerAcl).add("useragentAcl", useragentAcl).add("logRetention", logRetention);
-   }
-
-   @Override
-   public String toString() {
-      return string().toString();
-   }
-
-   public int compareTo(ContainerCDNMetadata o) {
-      if (getName() == null)
-         return -1;
-      return (this == o) ? 0 : getName().compareTo(o.getName());
-   }
-}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/CDNContainerApi.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/CDNContainerApi.java
new file mode 100644
index 0000000..a659fa1
--- /dev/null
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/CDNContainerApi.java
@@ -0,0 +1,63 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.hpcloud.objectstorage.extensions;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.hpcloud.objectstorage.domain.CDNContainer;
+import org.jclouds.hpcloud.objectstorage.options.ListCDNContainerOptions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides synchronous access to HP Cloud Object Storage via the REST API.
+ * 
+ * <p/>
+ * All commands return a ListenableFuture of the result. Any exceptions incurred during processing
+ * will be backend in an {@link java.util.concurrent.ExecutionException} as documented in {@link ListenableFuture#get()}.
+ * 
+ * @see org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi
+ * @see <a href="https://manage.hpcloud.com/pages/build/docs/objectstorage-lvs/api">HP Cloud Object
+ *      Storage API</a>
+ * @see CDNContainerAsyncApi
+ * @author Jeremy Daggett
+ */
+@Beta
+@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
+public interface CDNContainerApi  {
+   
+   FluentIterable<CDNContainer> list();
+   
+   FluentIterable<CDNContainer> list(ListCDNContainerOptions options);
+
+   CDNContainer get(String container);
+
+   URI enable(String container, long ttl);
+
+   URI enable(String container);
+
+   URI update(String container, long ttl);
+   
+   boolean disable(String container);
+
+}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/CDNContainerAsyncApi.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/CDNContainerAsyncApi.java
new file mode 100644
index 0000000..554c19d
--- /dev/null
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/CDNContainerAsyncApi.java
@@ -0,0 +1,144 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.hpcloud.objectstorage.extensions;
+
+import java.net.URI;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
+import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
+import org.jclouds.hpcloud.objectstorage.domain.CDNContainer;
+import org.jclouds.hpcloud.objectstorage.functions.ParseCDNContainerFromHeaders;
+import org.jclouds.hpcloud.objectstorage.functions.ParseCDNUriFromHeaders;
+import org.jclouds.hpcloud.objectstorage.options.ListCDNContainerOptions;
+import org.jclouds.hpcloud.objectstorage.reference.HPCloudObjectStorageHeaders;
+import org.jclouds.hpcloud.services.HPExtensionCDN;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.rest.annotations.Endpoint;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.functions.ReturnEmptyFluentIterableOnNotFoundOr404;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to HP Cloud Object Storage via the REST API.
+ * 
+ * <p/>
+ * All commands return a ListenableFuture of the result. Any exceptions incurred during processing
+ * will be backend in an {@link java.util.concurrent.ExecutionException} as documented in
+ * {@link ListenableFuture#get()}.
+ * 
+ * @see HPCloudObjectStorageApi
+ * @see <a href="https://manage.hpcloud.com/pages/build/docs/objectstorage-lvs/api">HP Cloud Object
+ *      Storage API</a>
+ * @author Jeremy Daggett
+ */
+@SkipEncoding('/')
+@RequestFilters(AuthenticateRequest.class)
+@Endpoint(HPExtensionCDN.class)
+public interface CDNContainerAsyncApi {
+   /**
+    * @see HPCloudObjectStorageApi#list()
+    */
+   @Beta
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @QueryParams(keys = "format", values = "json")
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   @Path("/")
+   ListenableFuture<FluentIterable<CDNContainer>> list();
+
+   /**
+    * @see HPCloudObjectStorageApi#list(ListCDNContainerOptions)
+    */
+   @Beta
+   @GET
+   @Consumes(MediaType.APPLICATION_JSON)
+   @QueryParams(keys = "format", values = "json")
+   @ExceptionParser(ReturnEmptyFluentIterableOnNotFoundOr404.class)
+   @Path("/")
+   ListenableFuture<FluentIterable<CDNContainer>> list(ListCDNContainerOptions options);
+
+   /**
+    * @see HPCloudObjectStorageApi#get(String)
+    */
+   @Beta
+   @HEAD
+   @ResponseParser(ParseCDNContainerFromHeaders.class)
+   @ExceptionParser(ReturnNullOnContainerNotFound.class)
+   @Path("/{container}")
+   ListenableFuture<CDNContainer> get(@PathParam("container") String container);
+
+   /**
+    * @see HPCloudObjectStorageApi#enable(String, long)
+    */
+   @Beta
+   @PUT
+   @Path("/{container}")
+   @Headers(keys = HPCloudObjectStorageHeaders.CDN_ENABLED, values = "True")
+   @ResponseParser(ParseCDNUriFromHeaders.class)
+   ListenableFuture<URI> enable(@PathParam("container") String container,
+            @HeaderParam(HPCloudObjectStorageHeaders.CDN_TTL) long ttl);
+
+   /**
+    * @see HPCloudObjectStorageApi#enable(String)
+    */
+   @Beta
+   @PUT
+   @Path("/{container}")
+   @Headers(keys = HPCloudObjectStorageHeaders.CDN_ENABLED, values = "True")
+   @ResponseParser(ParseCDNUriFromHeaders.class)
+   ListenableFuture<URI> enable(@PathParam("container") String container);
+
+   /**
+    * @see HPCloudObjectStorageApi#update(String, long)
+    */
+   @Beta
+   @POST
+   @Path("/{container}")
+   @ResponseParser(ParseCDNUriFromHeaders.class)
+   ListenableFuture<URI> update(@PathParam("container") String container,
+            @HeaderParam(HPCloudObjectStorageHeaders.CDN_TTL) long ttl);
+
+   /**
+    * @see HPCloudObjectStorageApi#disable(String)
+    */
+   @Beta
+   @PUT
+   @Path("/{container}")
+   @Headers(keys = HPCloudObjectStorageHeaders.CDN_ENABLED, values = "False")
+   ListenableFuture<Boolean> disable(@PathParam("container") String container);
+
+}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/HPCloudCDNAsyncClient.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/HPCloudCDNAsyncClient.java
deleted file mode 100644
index c61019d..0000000
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/HPCloudCDNAsyncClient.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.hpcloud.objectstorage.extensions;
-
-import java.net.URI;
-import java.util.Set;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.HEAD;
-import javax.ws.rs.HeaderParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.core.MediaType;
-
-import org.jclouds.blobstore.functions.ReturnNullOnContainerNotFound;
-import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageClient;
-import org.jclouds.hpcloud.objectstorage.domain.ContainerCDNMetadata;
-import org.jclouds.hpcloud.objectstorage.functions.ParseCDNUriFromHeaders;
-import org.jclouds.hpcloud.objectstorage.functions.ParseContainerCDNMetadataFromHeaders;
-import org.jclouds.hpcloud.objectstorage.options.ListCDNContainerOptions;
-import org.jclouds.hpcloud.objectstorage.reference.HPCloudObjectStorageHeaders;
-import org.jclouds.hpcloud.services.HPExtensionCDN;
-import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
-import org.jclouds.rest.annotations.Endpoint;
-import org.jclouds.rest.annotations.ExceptionParser;
-import org.jclouds.rest.annotations.Headers;
-import org.jclouds.rest.annotations.QueryParams;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.SkipEncoding;
-
-import com.google.common.annotations.Beta;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides asynchronous access to HP Cloud Object Storage via the REST API.
- * 
- * <p/>All commands return a ListenableFuture of the result. Any exceptions incurred
- * during processing will be backend in an {@link java.util.concurrent.ExecutionException} as documented in
- * {@link ListenableFuture#get()}.
- * 
- * @see HPCloudObjectStorageClient
- * @see <a href="https://manage.hpcloud.com/pages/build/docs/objectstorage-lvs/api">HP Cloud Object Storage API</a>
- * @author Jeremy Daggett
- */
-@SkipEncoding('/')
-@RequestFilters(AuthenticateRequest.class)
-@Endpoint(HPExtensionCDN.class)
-public interface HPCloudCDNAsyncClient {
-
-   /**
-    * @see HPCloudObjectStorageClient#listCDNContainers(ListCDNContainerOptions...)
-    */
-   @Beta
-   @GET
-   @Consumes(MediaType.APPLICATION_JSON)
-   @QueryParams(keys = "format", values = "json")
-   @Path("/")
-   ListenableFuture<? extends Set<ContainerCDNMetadata>> listCDNContainers(ListCDNContainerOptions... options);
-   
-   /**
-    * @see HPCloudObjectStorageClient#getCDNMetadata(String)
-    */
-   @Beta
-   @HEAD
-   @ResponseParser(ParseContainerCDNMetadataFromHeaders.class)
-   @ExceptionParser(ReturnNullOnContainerNotFound.class)
-   @Path("/{container}")
-   ListenableFuture<ContainerCDNMetadata> getCDNMetadata(@PathParam("container") String container);
-
-   /**
-    * @see HPCloudObjectStorageClient#enableCDN(String, long)
-    */
-   @Beta
-   @PUT
-   @Path("/{container}")
-   @Headers(keys = HPCloudObjectStorageHeaders.CDN_ENABLED, values = "True")
-   @ResponseParser(ParseCDNUriFromHeaders.class)
-   ListenableFuture<URI> enableCDN(@PathParam("container") String container,
-                                   @HeaderParam(HPCloudObjectStorageHeaders.CDN_TTL) long ttl);
-
-   /**
-    * @see HPCloudObjectStorageClient#enableCDN(String)
-    */
-   @Beta
-   @PUT
-   @Path("/{container}")
-   @Headers(keys = HPCloudObjectStorageHeaders.CDN_ENABLED, values = "True")
-   @ResponseParser(ParseCDNUriFromHeaders.class)
-   ListenableFuture<URI> enableCDN(@PathParam("container") String container);
-
-   /**
-    * @see HPCloudObjectStorageClient#updateCDN(String, long)
-    */
-   @Beta
-   @POST
-   @Path("/{container}")
-   @ResponseParser(ParseCDNUriFromHeaders.class)
-   ListenableFuture<URI> updateCDN(@PathParam("container") String container,
-                                   @HeaderParam(HPCloudObjectStorageHeaders.CDN_TTL) long ttl);
-
-   /**
-    * @see HPCloudObjectStorageClient#disableCDN(String)
-    */
-   @Beta
-   @PUT
-   @Path("/{container}")
-   @Headers(keys = HPCloudObjectStorageHeaders.CDN_ENABLED, values = "False")
-   ListenableFuture<Boolean> disableCDN(@PathParam("container") String container);
-
-}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/HPCloudCDNClient.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/HPCloudCDNClient.java
deleted file mode 100644
index d55090a..0000000
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/extensions/HPCloudCDNClient.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.hpcloud.objectstorage.extensions;
-
-import java.net.URI;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.jclouds.concurrent.Timeout;
-import org.jclouds.hpcloud.objectstorage.domain.ContainerCDNMetadata;
-import org.jclouds.hpcloud.objectstorage.options.ListCDNContainerOptions;
-
-import com.google.common.annotations.Beta;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides synchronous access to HP Cloud Object Storage via the REST API.
- * 
- * <p/>
- * All commands return a ListenableFuture of the result. Any exceptions incurred during processing
- * will be backend in an {@link java.util.concurrent.ExecutionException} as documented in {@link ListenableFuture#get()}.
- * 
- * @see org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageClient
- * @see <a href="https://manage.hpcloud.com/pages/build/docs/objectstorage-lvs/api">HP Cloud Object
- *      Storage API</a>
- * @author Jeremy Daggett
- */
-@Timeout(duration = 120, timeUnit = TimeUnit.SECONDS)
-public interface HPCloudCDNClient  {
-
-   @Beta
-   Set<ContainerCDNMetadata> listCDNContainers(ListCDNContainerOptions... options);
-
-   @Beta
-   ContainerCDNMetadata getCDNMetadata(String container);
-
-   @Beta
-   URI enableCDN(String container, long ttl);
-
-   @Beta
-   URI enableCDN(String container);
-
-   @Beta
-   URI updateCDN(String container, long ttl);
-   
-   @Beta
-   boolean disableCDN(String container);
-
-}
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/functions/ParseCDNContainerFromHeaders.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/functions/ParseCDNContainerFromHeaders.java
new file mode 100644
index 0000000..96e63f0
--- /dev/null
+++ b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/functions/ParseCDNContainerFromHeaders.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.hpcloud.objectstorage.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Lists.newArrayList;
+
+import java.net.URI;
+import java.util.List;
+
+import org.jclouds.hpcloud.objectstorage.domain.CDNContainer;
+import org.jclouds.hpcloud.objectstorage.reference.HPCloudObjectStorageHeaders;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.swift.domain.AccountMetadata;
+import org.jclouds.rest.InvocationContext;
+
+import com.google.common.base.Function;
+import com.google.common.base.Splitter;
+
+/**
+ * This parses {@link AccountMetadata} from HTTP headers.
+ * 
+ * @author James Murty
+ */
+public class ParseCDNContainerFromHeaders implements
+         Function<HttpResponse, CDNContainer>, InvocationContext<ParseCDNContainerFromHeaders> {
+
+   private HttpRequest request;
+
+   /**
+    * parses the http response headers to create a new {@link CDNContainer} object.
+    */
+   public CDNContainer apply(final HttpResponse from) {
+      String cdnUri = checkNotNull(from.getFirstHeaderOrNull(HPCloudObjectStorageHeaders.CDN_URI),
+               HPCloudObjectStorageHeaders.CDN_URI);
+      String cdnTTL = checkNotNull(from.getFirstHeaderOrNull(HPCloudObjectStorageHeaders.CDN_TTL),
+               HPCloudObjectStorageHeaders.CDN_TTL);
+      String cdnEnabled = checkNotNull(from.getFirstHeaderOrNull(HPCloudObjectStorageHeaders.CDN_ENABLED),
+               HPCloudObjectStorageHeaders.CDN_ENABLED);
+      if (cdnUri == null) {
+         // CDN is not enabled for this container.
+         return null;
+      } else {
+         // just need the name from the path
+         List<String> parts = newArrayList(Splitter.on('/').split(request.getEndpoint().getPath()));
+
+         return CDNContainer.builder().name(parts.get(parts.size() - 1))
+               .CDNEnabled(Boolean.parseBoolean(cdnEnabled)).ttl(Long.parseLong(cdnTTL)).CDNUri(URI.create(cdnUri))
+               .build();
+      }
+   }
+
+   @Override
+   public ParseCDNContainerFromHeaders setContext(HttpRequest request) {
+      this.request = request;
+      return this;
+   }
+}
\ No newline at end of file
diff --git a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/functions/ParseContainerCDNMetadataFromHeaders.java b/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/functions/ParseContainerCDNMetadataFromHeaders.java
deleted file mode 100644
index 386cb00..0000000
--- a/providers/hpcloud-objectstorage/src/main/java/org/jclouds/hpcloud/objectstorage/functions/ParseContainerCDNMetadataFromHeaders.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.hpcloud.objectstorage.functions;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.collect.Lists.newArrayList;
-
-import java.net.URI;
-import java.util.List;
-
-import org.jclouds.hpcloud.objectstorage.domain.ContainerCDNMetadata;
-import org.jclouds.hpcloud.objectstorage.reference.HPCloudObjectStorageHeaders;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.openstack.swift.domain.AccountMetadata;
-import org.jclouds.rest.InvocationContext;
-
-import com.google.common.base.Function;
-import com.google.common.base.Splitter;
-
-/**
- * This parses {@link AccountMetadata} from HTTP headers.
- * 
- * @author James Murty
- */
-public class ParseContainerCDNMetadataFromHeaders implements
-         Function<HttpResponse, ContainerCDNMetadata>, InvocationContext<ParseContainerCDNMetadataFromHeaders> {
-
-   private HttpRequest request;
-
-   /**
-    * parses the http response headers to create a new {@link ContainerCDNMetadata} object.
-    */
-   public ContainerCDNMetadata apply(final HttpResponse from) {
-      String cdnUri = checkNotNull(from.getFirstHeaderOrNull(HPCloudObjectStorageHeaders.CDN_URI),
-               HPCloudObjectStorageHeaders.CDN_URI);
-      String cdnTTL = checkNotNull(from.getFirstHeaderOrNull(HPCloudObjectStorageHeaders.CDN_TTL),
-               HPCloudObjectStorageHeaders.CDN_TTL);
-      String cdnEnabled = checkNotNull(from.getFirstHeaderOrNull(HPCloudObjectStorageHeaders.CDN_ENABLED),
-               HPCloudObjectStorageHeaders.CDN_ENABLED);
-      if (cdnUri == null) {
-         // CDN is not enabled for this container.
-         return null;
-      } else {
-         // just need the name from the path
-         List<String> parts = newArrayList(Splitter.on('/').split(request.getEndpoint().getPath()));
-
-         return ContainerCDNMetadata.builder().name(parts.get(parts.size() - 1))
-               .CDNEnabled(Boolean.parseBoolean(cdnEnabled)).ttl(Long.parseLong(cdnTTL)).CDNUri(URI.create(cdnUri))
-               .build();
-      }
-   }
-
-   @Override
-   public ParseContainerCDNMetadataFromHeaders setContext(HttpRequest request) {
-      this.request = request;
-      return this;
-   }
-}
\ No newline at end of file
diff --git a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageClientLiveTest.java b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageClientLiveTest.java
index 36b7256..ccb1918 100644
--- a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageClientLiveTest.java
+++ b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/HPCloudObjectStorageClientLiveTest.java
@@ -22,27 +22,28 @@
 import static org.testng.Assert.assertTrue;
 
 import java.net.URI;
-import java.util.Set;
 
-import org.jclouds.hpcloud.objectstorage.domain.ContainerCDNMetadata;
+import org.jclouds.hpcloud.objectstorage.domain.CDNContainer;
 import org.jclouds.hpcloud.objectstorage.options.ListCDNContainerOptions;
 import org.jclouds.openstack.swift.CommonSwiftClientLiveTest;
 import org.jclouds.openstack.swift.domain.SwiftObject;
 import org.testng.annotations.Test;
 
+import com.google.common.collect.FluentIterable;
+
 /**
  * 
  * @author Adrian Cole
  */
 @Test(groups = "live", testName = "HPCloudObjectStorageClientLiveTest")
-public class HPCloudObjectStorageClientLiveTest extends CommonSwiftClientLiveTest<HPCloudObjectStorageClient> {
+public class HPCloudObjectStorageClientLiveTest extends CommonSwiftClientLiveTest<HPCloudObjectStorageApi> {
    
    public HPCloudObjectStorageClientLiveTest(){
       provider = "hpcloud-objectstorage";
    }
    
    @Override
-   public HPCloudObjectStorageClient getApi() {
+   public HPCloudObjectStorageApi getApi() {
       return view.unwrap(HPCloudObjectStorageApiMetadata.CONTEXT_TOKEN).getApi();
    }
 
@@ -61,49 +62,49 @@
       final String containerNameWithoutCDN = getContainerName();
       try {
          try {
-            getApi().getCDNExtension().get().disableCDN(containerNameWithCDN);
-            getApi().getCDNExtension().get().disableCDN(containerNameWithoutCDN);
+            getApi().getCDNExtension().get().disable(containerNameWithCDN);
+            getApi().getCDNExtension().get().disable(containerNameWithoutCDN);
          } catch (Exception e) {
             e.printStackTrace();
          }
-         ContainerCDNMetadata cdnMetadata = null;
+         CDNContainer cdnMetadata = null;
 
          // Enable CDN with PUT for one container
-         final URI cdnUri = getApi().getCDNExtension().get().enableCDN(containerNameWithCDN);
+         final URI cdnUri = getApi().getCDNExtension().get().enable(containerNameWithCDN);
          assertTrue(cdnUri != null);
 
          // Confirm CDN is enabled via HEAD request and has default TTL
-         cdnMetadata = getApi().getCDNExtension().get().getCDNMetadata(containerNameWithCDN);
+         cdnMetadata = getApi().getCDNExtension().get().get(containerNameWithCDN);
 
          assertTrue(cdnMetadata.isCDNEnabled());
 
          assertEquals(cdnMetadata.getCDNUri(), cdnUri);
 
-         cdnMetadata = getApi().getCDNExtension().get().getCDNMetadata(containerNameWithoutCDN);
+         cdnMetadata = getApi().getCDNExtension().get().get(containerNameWithoutCDN);
          assert cdnMetadata == null || !cdnMetadata.isCDNEnabled() : containerNameWithoutCDN
                   + " should not have metadata";
 
-         assert getApi().getCDNExtension().get().getCDNMetadata("DoesNotExist") == null;
+         assert getApi().getCDNExtension().get().get("DoesNotExist") == null;
 
          // List CDN metadata for containers, and ensure all CDN info is
          // available for enabled
          // container
-         Set<ContainerCDNMetadata> cdnMetadataList = getApi().getCDNExtension().get().listCDNContainers();
+         FluentIterable<CDNContainer> cdnMetadataList = getApi().getCDNExtension().get().list();
          assertTrue(cdnMetadataList.size() >= 1);
 
          final long initialTTL = cdnMetadata.getTTL();
-         assertTrue(cdnMetadataList.contains(ContainerCDNMetadata.builder().name(containerNameWithCDN)
+         assertTrue(cdnMetadataList.contains(CDNContainer.builder().name(containerNameWithCDN)
                .CDNEnabled(true).ttl(initialTTL).CDNUri(cdnUri).build()));
 
          /*
           * Test listing with options FIXFIX cdnMetadataList =
-          * getApi().listCDNContainers(ListCDNContainerOptions.Builder.enabledOnly());
-          * assertTrue(Iterables.all(cdnMetadataList, new Predicate<ContainerCDNMetadata>() { public
-          * boolean apply(ContainerCDNMetadata cdnMetadata) { return cdnMetadata.isCDNEnabled(); }
+          * getApi().list(ListCDNContainerOptions.Builder.enabledOnly());
+          * assertTrue(Iterables.all(cdnMetadataList, new Predicate<CDNContainer>() { public
+          * boolean apply(CDNContainer cdnMetadata) { return cdnMetadata.isCDNEnabled(); }
           * }));
           */
 
-         cdnMetadataList = getApi().getCDNExtension().get().listCDNContainers(
+         cdnMetadataList = getApi().getCDNExtension().get().list(
                   ListCDNContainerOptions.Builder.afterMarker(
                            containerNameWithCDN.substring(0, containerNameWithCDN.length() - 1)).maxResults(1));
          assertEquals(cdnMetadataList.size(), 1);
@@ -111,9 +112,9 @@
          // Enable CDN with PUT for the same container, this time with a custom
          // TTL
          long ttl = 4000;
-         getApi().getCDNExtension().get().enableCDN(containerNameWithCDN, ttl);
+         getApi().getCDNExtension().get().enable(containerNameWithCDN, ttl);
 
-         cdnMetadata = getApi().getCDNExtension().get().getCDNMetadata(containerNameWithCDN);
+         cdnMetadata = getApi().getCDNExtension().get().get(containerNameWithCDN);
 
          assertTrue(cdnMetadata.isCDNEnabled());
    
@@ -121,23 +122,23 @@
 
          // Check POST by updating TTL settings
          ttl = minimumTTL;
-         getApi().getCDNExtension().get().updateCDN(containerNameWithCDN, minimumTTL);
+         getApi().getCDNExtension().get().update(containerNameWithCDN, minimumTTL);
 
-         cdnMetadata = getApi().getCDNExtension().get().getCDNMetadata(containerNameWithCDN);
+         cdnMetadata = getApi().getCDNExtension().get().get(containerNameWithCDN);
          assertTrue(cdnMetadata.isCDNEnabled());
 
          assertEquals(cdnMetadata.getTTL(), minimumTTL);
 
          // Confirm that minimum allowed value for TTL is 3600, lower values are
          // ignored.
-         getApi().getCDNExtension().get().updateCDN(containerNameWithCDN, 3599L);
-         cdnMetadata = getApi().getCDNExtension().get().getCDNMetadata(containerNameWithCDN);
+         getApi().getCDNExtension().get().update(containerNameWithCDN, 3599L);
+         cdnMetadata = getApi().getCDNExtension().get().get(containerNameWithCDN);
          assertEquals(cdnMetadata.getTTL(), 3599L);
 
          // Disable CDN with POST
-         assertTrue(getApi().getCDNExtension().get().disableCDN(containerNameWithCDN));
+         assertTrue(getApi().getCDNExtension().get().disable(containerNameWithCDN));
 
-         cdnMetadata = getApi().getCDNExtension().get().getCDNMetadata(containerNameWithCDN);
+         cdnMetadata = getApi().getCDNExtension().get().get(containerNameWithCDN);
          assertEquals(cdnMetadata.isCDNEnabled(), false);
       } catch (Exception e) {
          e.printStackTrace();
diff --git a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobRequestSignerTest.java b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobRequestSignerTest.java
index da1c269..ab0351b 100644
--- a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobRequestSignerTest.java
+++ b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobRequestSignerTest.java
@@ -44,7 +44,7 @@
 public class HPCloudObjectStorageBlobRequestSignerTest extends BaseHPCloudObjectStorageBlobStoreExpectTest {
 
    Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder().put(
-            keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess).build();
+            keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess).build();
 
    public void testSignGetBlob() {
 
diff --git a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStoreExpectTest.java b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStoreExpectTest.java
index 1651065..20e6eaf 100644
--- a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStoreExpectTest.java
+++ b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/blobstore/HPCloudObjectStorageBlobStoreExpectTest.java
@@ -39,7 +39,7 @@
 
     public void testListObjectsWhenResponseIs2xx() throws Exception {
         Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder().put(
-                keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess).build();
+                 keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess).build();
 
         BlobStore clientWhenLocationsExist = requestsSendResponses(requestResponseMap);
 
diff --git a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/functions/ParseContainerCDNMetadataListFromJsonResponseTest.java b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/functions/ParseContainerCDNMetadataListFromJsonResponseTest.java
deleted file mode 100644
index b3194b5..0000000
--- a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/functions/ParseContainerCDNMetadataListFromJsonResponseTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.hpcloud.objectstorage.functions;
-
-import static org.testng.Assert.assertEquals;
-
-import java.io.InputStream;
-import java.net.URI;
-import java.util.Set;
-import java.util.SortedSet;
-
-import org.jclouds.hpcloud.objectstorage.domain.ContainerCDNMetadata;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.functions.ParseJson;
-import org.jclouds.json.config.GsonModule;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.TypeLiteral;
-
-/**
- * Tests behavior of {@code ParseContainerCDNMetadataListFromJsonResponse}
- * 
- * @author Jeremy Daggett
- */
-@Test(groups = "unit")
-public class ParseContainerCDNMetadataListFromJsonResponseTest {
-   Injector i = Guice.createInjector(new GsonModule());
-
-   @Test
-   public void testApplyInputStream() {
-
-      InputStream is = getClass().getResourceAsStream("/test_list_cdn.json");
-      
-      Set<ContainerCDNMetadata> expects = ImmutableSet.of(
-         ContainerCDNMetadata.builder().name("hpcloud-blobstore.testCDNOperationsContainerWithCDN").CDNEnabled(false).ttl(3600)
-                  .CDNUri(URI.create("https://cdnmgmt.hpcloud.net:8080/v1/AUTH_test/")).build(),
-            ContainerCDNMetadata.builder().name("hpcloud-blobstore5").CDNEnabled(true).ttl(28800)
-                  .CDNUri(URI.create("https://cdnmgmt.hpcloud.net:8080/v1/AUTH_test/")).build(),
-            ContainerCDNMetadata.builder().name("hpcloud-cfcdnint.testCDNOperationsContainerWithCDN").CDNEnabled(false).ttl(3600)
-                  .CDNUri(URI.create("https://cdnmgmt.hpcloud.net:8080/v1/AUTH_test/")).build());
-      
-      ParseJson<SortedSet<ContainerCDNMetadata>> parser = i.getInstance(
-            Key.get(new TypeLiteral<ParseJson<SortedSet<ContainerCDNMetadata>>>() {
-            }));
-      
-      assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload(is).build()), expects);
-   }
-}
diff --git a/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/parse/CDNContainersTest.java b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/parse/CDNContainersTest.java
new file mode 100644
index 0000000..389b031
--- /dev/null
+++ b/providers/hpcloud-objectstorage/src/test/java/org/jclouds/hpcloud/objectstorage/parse/CDNContainersTest.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.hpcloud.objectstorage.parse;
+
+import java.net.URI;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.hpcloud.objectstorage.domain.CDNContainer;
+import org.jclouds.json.BaseItemParserTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "CDNContainersTest")
+public class CDNContainersTest extends BaseItemParserTest<FluentIterable<CDNContainer>> {
+
+   @Override
+   public String resource() {
+      return "/test_list_cdn.json";
+   }
+
+   @Override
+   @Consumes(MediaType.APPLICATION_JSON)
+   public FluentIterable<CDNContainer> expected() {
+      return FluentIterable.from(ImmutableSet.of(
+               CDNContainer.builder().name("hpcloud-blobstore.testCDNOperationsContainerWithCDN").CDNEnabled(false)
+                        .ttl(3600).CDNUri(URI.create("https://cdnmgmt.hpcloud.net:8080/v1/AUTH_test/")).build(),
+               CDNContainer.builder().name("hpcloud-blobstore5").CDNEnabled(true).ttl(28800)
+                        .CDNUri(URI.create("https://cdnmgmt.hpcloud.net:8080/v1/AUTH_test/")).build(),
+               CDNContainer.builder().name("hpcloud-cfcdnint.testCDNOperationsContainerWithCDN").CDNEnabled(false)
+                        .ttl(3600).CDNUri(URI.create("https://cdnmgmt.hpcloud.net:8080/v1/AUTH_test/")).build()));
+   }
+}
diff --git a/providers/pom.xml b/providers/pom.xml
index 53ca476..723c6a7 100644
--- a/providers/pom.xml
+++ b/providers/pom.xml
@@ -73,5 +73,7 @@
         <module>trystack-nova</module>
         <module>rackspace-cloudservers-us</module>
         <module>rackspace-cloudservers-uk</module>
+        <module>aws-sqs</module>
+        <module>glesys</module>
     </modules>
 </project>
diff --git a/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/SoftLayerExperimentLiveTest.java b/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/SoftLayerExperimentLiveTest.java
index c98091b..f750165 100644
--- a/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/SoftLayerExperimentLiveTest.java
+++ b/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/SoftLayerExperimentLiveTest.java
@@ -36,7 +36,7 @@
 public class SoftLayerExperimentLiveTest extends BaseComputeServiceContextLiveTest {
 
    public SoftLayerExperimentLiveTest() {
-      provider = "glesys";
+      provider = "softlayer";
    }
 
    @Test
diff --git a/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/SoftLayerTemplateBuilderLiveTest.java b/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/SoftLayerTemplateBuilderLiveTest.java
index 181e380..4d7b9aa 100644
--- a/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/SoftLayerTemplateBuilderLiveTest.java
+++ b/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/SoftLayerTemplateBuilderLiveTest.java
@@ -63,7 +63,7 @@
             // For each os-type both 32- and 64-bit are supported.
             switch (input.family) {
             case UBUNTU:
-               return input.version.equals("") || input.version.equals("10.04") || input.version.equals("8");
+               return input.version.equals("") || input.version.equals("10.04") || input.version.equals("12.04") || input.version.equals("8");
             case DEBIAN:
                return input.version.equals("") || input.version.matches("[56].0");
             case FEDORA:
@@ -85,7 +85,7 @@
    @Test
    public void testDefaultTemplateBuilder() throws IOException {
       Template defaultTemplate = view.getComputeService().templateBuilder().build();
-      assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "10.04");
+      assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "12.04");
       assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
       assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
       assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);
@@ -212,6 +212,7 @@
 
    @Override
    protected Set<String> getIso3166Codes() {
-      return ImmutableSet.<String> of("SG", "NL", "US-CA", "US-TX", "US-VA", "US-WA", "US-TX");
+      return ImmutableSet.<String> of("SG", "US-CA", "US-TX", "US-VA", "US-WA");
    }
+
 }
\ No newline at end of file
diff --git a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/BaseSoftLayerClientLiveTest.java b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/BaseSoftLayerClientLiveTest.java
index f8c6eab8..8732b7a 100644
--- a/providers/softlayer/src/test/java/org/jclouds/softlayer/features/BaseSoftLayerClientLiveTest.java
+++ b/providers/softlayer/src/test/java/org/jclouds/softlayer/features/BaseSoftLayerClientLiveTest.java
@@ -33,6 +33,10 @@
 @Test(groups = "live")
 public class BaseSoftLayerClientLiveTest extends BaseComputeServiceContextLiveTest {
 
+   public BaseSoftLayerClientLiveTest() {
+      this.provider = "softlayer";
+   }
+
    protected RestContext<SoftLayerClient, SoftLayerAsyncClient> socontext;
 
    @BeforeGroups(groups = { "integration", "live" })
diff --git a/resources/NOTICE.txt b/resources/NOTICE.txt
index b0a56c7..ab77979 100644
--- a/resources/NOTICE.txt
+++ b/resources/NOTICE.txt
@@ -64,3 +64,9 @@
 This product includes software developed at Hewlett-Packard
 Copyright (c) 2011-2012 Hewlett-Packard Development Company, L.P
 
+This product includes software developed at Cloudsoft
+Copyright (c) 2011-2012 Cloudsoft Corporation, Ltd.
+
+This product includes software developed at MuleSoft
+Copyright (c) 2012 MuleSoft Inc.
+
diff --git a/sandbox-apis/sqs/pom.xml b/sandbox-apis/sqs/pom.xml
deleted file mode 100644
index da72c61..0000000
--- a/sandbox-apis/sqs/pom.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    Licensed to jclouds, Inc. (jclouds) under one or more
-    contributor license agreements.  See the NOTICE file
-    distributed with this work for additional information
-    regarding copyright ownership.  jclouds licenses this file
-    to you under the Apache License, Version 2.0 (the
-    "License"); you may not use this file except in compliance
-    with the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing,
-    software distributed under the License is distributed on an
-    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    KIND, either express or implied.  See the License for the
-    specific language governing permissions and limitations
-    under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <parent>
-        <groupId>org.jclouds</groupId>
-        <artifactId>jclouds-project</artifactId>
-        <version>1.5.0-SNAPSHOT</version>
-        <relativePath>../../project/pom.xml</relativePath>
-    </parent>
-    <groupId>org.jclouds.api</groupId>
-    <artifactId>sqs</artifactId>
-    <name>jcloud sqs api</name>
-    <description>jclouds components to access an implementation of Simple Queue Service</description>
-    <packaging>bundle</packaging>
-
-    <properties>
-        <test.sqs.endpoint>https://sqs.us-east-1.amazonaws.com</test.sqs.endpoint>
-        <test.sqs.api-version>2009-02-01</test.sqs.api-version>
-        <test.sqs.build-version></test.sqs.build-version>
-        <test.sqs.identity>${test.aws.identity}</test.sqs.identity>
-        <test.sqs.credential>${test.aws.credential}</test.sqs.credential>
-
-        <jclouds.osgi.export>org.jclouds.sqs*;version="${project.version}"</jclouds.osgi.export>
-        <jclouds.osgi.import>org.jclouds*;version="${project.version}",*</jclouds.osgi.import>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.jclouds.common</groupId>
-            <artifactId>aws-common</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.jclouds</groupId>
-            <artifactId>jclouds-core</artifactId>
-            <version>${project.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.jclouds.driver</groupId>
-            <artifactId>jclouds-log4j</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-
-    <profiles>
-        <profile>
-            <id>live</id>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-surefire-plugin</artifactId>
-                        <executions>
-                            <execution>
-                                <id>integration</id>
-                                <phase>integration-test</phase>
-                                <goals>
-                                    <goal>test</goal>
-                                </goals>
-                                <configuration>
-                                    <systemPropertyVariables>
-                                        <test.sqs.endpoint>${test.sqs.endpoint}</test.sqs.endpoint>
-                                        <test.sqs.api-version>${test.sqs.api-version}</test.sqs.api-version>
-                                        <test.sqs.build-version>${test.sqs.build-version}</test.sqs.build-version>
-                                        <test.sqs.identity>${test.sqs.identity}</test.sqs.identity>
-                                        <test.sqs.credential>${test.sqs.credential}</test.sqs.credential>
-                                    </systemPropertyVariables>
-                                </configuration>
-                            </execution>
-                        </executions>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-    </profiles>
-
-</project>
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSAsyncClient.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSAsyncClient.java
deleted file mode 100644
index c28f03f..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSAsyncClient.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs;
-
-import static org.jclouds.sqs.reference.SQSParameters.ACTION;
-import static org.jclouds.sqs.reference.SQSParameters.VERSION;
-
-import java.util.Set;
-
-import javax.annotation.Nullable;
-import javax.ws.rs.FormParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-
-import org.jclouds.aws.filters.FormSigner;
-import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
-import org.jclouds.rest.annotations.EndpointParam;
-import org.jclouds.rest.annotations.FormParams;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.VirtualHost;
-import org.jclouds.sqs.domain.Queue;
-import org.jclouds.sqs.functions.QueueLocation;
-import org.jclouds.sqs.options.CreateQueueOptions;
-import org.jclouds.sqs.options.ListQueuesOptions;
-import org.jclouds.sqs.xml.RegexListQueuesResponseHandler;
-import org.jclouds.sqs.xml.RegexMD5Handler;
-import org.jclouds.sqs.xml.RegexQueueHandler;
-
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * Provides access to SQS via their REST API.
- * <p/>
- * 
- * @author Adrian Cole
- */
-@RequestFilters(FormSigner.class)
-@FormParams(keys = VERSION, values = SQSAsyncClient.VERSION)
-@VirtualHost
-public interface SQSAsyncClient {
-   public static final String VERSION = "2009-02-01";
-
-   /**
-    * @see SQSClient#listQueuesInRegion
-    */
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "ListQueues")
-   @ResponseParser(RegexListQueuesResponseHandler.class)
-   ListenableFuture<? extends Set<Queue>> listQueuesInRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
-            ListQueuesOptions... options);
-
-   /**
-    * @see SQSClient#createQueueInRegion
-    */
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "CreateQueue")
-   @ResponseParser(RegexQueueHandler.class)
-   ListenableFuture<Queue> createQueueInRegion(
-            @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region,
-            @FormParam("QueueName") String queueName, CreateQueueOptions... options);
-
-   /**
-    * @see SQSClient#deleteQueue
-    */
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "DeleteQueue")
-   ListenableFuture<Void> deleteQueue(@EndpointParam(parser = QueueLocation.class) Queue queue);
-
-   /**
-    * @see SQSClient#sendMessage
-    */
-   @POST
-   @Path("/")
-   @FormParams(keys = ACTION, values = "SendMessage")
-   @ResponseParser(RegexMD5Handler.class)
-   ListenableFuture<byte[]> sendMessage(@EndpointParam(parser = QueueLocation.class) Queue queue,
-            @FormParam("MessageBody") String message);
-
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSClient.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSClient.java
deleted file mode 100644
index 93dd31b..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSClient.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import javax.annotation.Nullable;
-
-import org.jclouds.sqs.domain.Queue;
-import org.jclouds.sqs.options.CreateQueueOptions;
-import org.jclouds.sqs.options.ListQueuesOptions;
-import org.jclouds.concurrent.Timeout;
-
-/**
- * Provides access to SQS via their REST API.
- * <p/>
- * 
- * @author Adrian Cole
- */
-@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
-public interface SQSClient {
-
-   /**
-    * The ListQueues action returns a list of your queues. The maximum number of queues that can be
-    * returned is 1000. If you specify a value for the optional QueueNamePrefix parameter, only
-    * queues with a name beginning with the specified value are returned
-    * 
-    * @param region
-    *           Queues are Region-specific.
-    * @param options
-    *           specify prefix or other options
-    * 
-    * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/2009-02-01/APIReference/Query_QueryListQueues.html"
-    *      />
-    */
-   Set<Queue> listQueuesInRegion(@Nullable String region, ListQueuesOptions... options);
-
-   /**
-    * 
-    * The CreateQueue action creates a new queue.
-    * <p/>
-    * When you request CreateQueue, you provide a name for the queue. To successfully create a new
-    * queue, you must provide a name that is unique within the scope of your own queues. If you
-    * provide the name of an existing queue, a new queue isn't created and an error isn't returned.
-    * Instead, the request succeeds and the queue URL for the existing queue is returned (for more
-    * information about queue URLs, see Queue and Message Identifiers in the Amazon SQS Developer
-    * Guide). Exception: if you provide a value for DefaultVisibilityTimeout that is different from
-    * the value for the existing queue, you receive an error.
-    * <h3>Note</h3>
-    * 
-    * If you delete a queue, you must wait at least 60 seconds before creating a queue with the same
-    * name.
-    * <p/>
-    * A default value for the queue's visibility timeout (30 seconds) is set when the queue is
-    * created. You can override this value with the DefaultVisibilityTimeout request parameter. For
-    * more information, see Visibility Timeout in the Amazon SQS Developer Guide.
-    * 
-    * @param region
-    *           Queues are Region-specific.
-    * @param queueName
-    *           The name to use for the queue created. Constraints: Maximum 80 characters;
-    *           alphanumeric characters, hyphens (-), and underscores (_) are allowed.
-    * @param options
-    *           like the visibility timeout (in seconds) to use for this queue.
-    */
-   Queue createQueueInRegion(@Nullable String region, String queueName, CreateQueueOptions... options);
-
-   /**
-    * The DeleteQueue action deletes the queue specified by the queue URL, regardless of whether the
-    * queue is empty. If the specified queue does not exist, SQS returns a successful response. <h3>
-    * Caution</h3>
-    * 
-    * Use DeleteQueue with care; once you delete your queue, any messages in the queue are no longer
-    * available.
-    * <p/>
-    * When you delete a queue, the deletion process takes up to 60 seconds. Requests you send
-    * involving that queue during the 60 seconds might succeed. For example, a SendMessage request
-    * might succeed, but after the 60 seconds, the queue and that message you sent no longer exist.
-    * Also, when you delete a queue, you must wait at least 60 seconds before creating a queue with
-    * the same name.
-    * <p/>
-    * We reserve the right to delete queues that have had no activity for more than 30 days. For
-    * more information, see About SQS Queues in the Amazon SQS Developer Guide.
-    * 
-    * @param queue
-    *           queue you want to delete
-    */
-   void deleteQueue(Queue queue);
-
-   /**
-    * The SendMessage action delivers a message to the specified queue. The maximum allowed message
-    * size is 8 KB.
-    * <p/>
-    * Important
-    * <p/>
-    * The following list shows the characters (in Unicode) allowed in your message, according to the
-    * W3C XML specification (for more information, go to http://www.w3.org/TR/REC-xml/#charsets). If
-    * you send any characters not included in the list, your request will be rejected.
-    * <p/>
-    * #x9 | #xA | #xD | [#x20 to #xD7FF] | [#xE000 to #xFFFD] | [#x10000 to #x10FFFF]
-    * 
-    * @param queue
-    *           queue you want to send to
-    * 
-    * @param message
-    *           The message to send. Type: String maximum 8 KB in size. For a list of allowed
-    *           characters, see the preceding important note
-    * @return md5 of the content sent
-    */
-   byte[] sendMessage(Queue queue, String message);
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSContextBuilder.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSContextBuilder.java
deleted file mode 100644
index 99be875..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSContextBuilder.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs;
-
-import java.util.List;
-import java.util.Properties;
-
-import org.jclouds.sqs.config.SQSRestClientModule;
-import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
-import org.jclouds.logging.jdk.config.JDKLoggingModule;
-import org.jclouds.rest.RestContextBuilder;
-
-import com.google.inject.Injector;
-import com.google.inject.Module;
-
-/**
- * Creates {@link SQSContext} or {@link Injector} instances based on the most commonly requested
- * arguments.
- * <p/>
- * Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
- * <p/>
- * <p/>
- * If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
- * {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
- * 
- * @author Adrian Cole
- * @see SQSContext
- */
-public class SQSContextBuilder extends RestContextBuilder<SQSClient, SQSAsyncClient> {
-
-   public SQSContextBuilder(Properties props) {
-      super(SQSClient.class, SQSAsyncClient.class, props);
-   }
-
-   @Override
-   protected void addClientModule(List<Module> modules) {
-      modules.add(new SQSRestClientModule());
-   }
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSPropertiesBuilder.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSPropertiesBuilder.java
deleted file mode 100644
index ef2b7eb..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/SQSPropertiesBuilder.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs;
-
-import static org.jclouds.Constants.PROPERTY_API_VERSION;
-import static org.jclouds.Constants.PROPERTY_ENDPOINT;
-import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
-import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
-
-import java.util.Properties;
-
-import org.jclouds.PropertiesBuilder;
-
-/**
- * Builds properties used in SQS Clients
- * 
- * @author Adrian Cole
- */
-public class SQSPropertiesBuilder extends PropertiesBuilder {
-   @Override
-   protected Properties defaultProperties() {
-      Properties properties = super.defaultProperties();
-      properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
-      properties.setProperty(PROPERTY_HEADER_TAG, "amz");
-      properties.setProperty(PROPERTY_API_VERSION, SQSAsyncClient.VERSION);
-      properties.setProperty(PROPERTY_ENDPOINT, "https://sqs.us-east-1.amazonaws.com");
-      return properties;
-   }
-
-   public SQSPropertiesBuilder() {
-      super();
-   }
-
-   public SQSPropertiesBuilder(Properties properties) {
-      super(properties);
-   }
-
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/config/SQSRestClientModule.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/config/SQSRestClientModule.java
deleted file mode 100644
index 7d34986..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/config/SQSRestClientModule.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.config;
-
-import org.jclouds.aws.config.FormSigningRestClientModule;
-import org.jclouds.http.RequiresHttp;
-import org.jclouds.rest.ConfiguresRestClient;
-import org.jclouds.sqs.SQSAsyncClient;
-import org.jclouds.sqs.SQSClient;
-
-/**
- * Configures the SQS connection.
- * 
- * @author Adrian Cole
- */
-@RequiresHttp
-@ConfiguresRestClient
-public class SQSRestClientModule extends FormSigningRestClientModule<SQSClient, SQSAsyncClient> {
-
-   public SQSRestClientModule() {
-      super(SQSClient.class, SQSAsyncClient.class);
-   }
-
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/domain/Queue.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/domain/Queue.java
deleted file mode 100644
index a6e0fbe..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/domain/Queue.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.domain;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.net.URI;
-
-/**
- * 
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
- *      />
- * @author Adrian Cole
- */
-public class Queue implements Comparable<Queue> {
-   private final String region;
-   private final String name;
-   private final URI location;
-
-   public Queue(String region, String name, URI location) {
-      this.region = checkNotNull(region,"region");
-      this.location = checkNotNull(location, "location");
-      this.name = checkNotNull(name, "name");
-   }
-
-   @Override
-   public int compareTo(Queue o) {
-      return location.toASCIIString().compareTo(o.location.toASCIIString());
-   }
-
-   public String getRegion() {
-      return region;
-   }
-   
-   public URI getLocation() {
-      return location;
-   }
-
-   public String getName() {
-      return name;
-   }
-
-   @Override
-   public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result = prime * result + ((location == null) ? 0 : location.hashCode());
-      result = prime * result + ((name == null) ? 0 : name.hashCode());
-      result = prime * result + ((region == null) ? 0 : region.hashCode());
-      return result;
-   }
-
-   @Override
-   public boolean equals(Object obj) {
-      if (this == obj)
-         return true;
-      if (obj == null)
-         return false;
-      if (getClass() != obj.getClass())
-         return false;
-      Queue other = (Queue) obj;
-      if (location == null) {
-         if (other.location != null)
-            return false;
-      } else if (!location.equals(other.location))
-         return false;
-      if (name == null) {
-         if (other.name != null)
-            return false;
-      } else if (!name.equals(other.name))
-         return false;
-      if (region == null) {
-         if (other.region != null)
-            return false;
-      } else if (!region.equals(other.region))
-         return false;
-      return true;
-   }
-
-   @Override
-   public String toString() {
-      return "Queue [location=" + location + ", name=" + name + ", region=" + region + "]";
-   }
-
-
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/functions/QueueLocation.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/functions/QueueLocation.java
deleted file mode 100644
index 9e2846b..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/functions/QueueLocation.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.functions;
-
-import java.net.URI;
-
-import javax.inject.Singleton;
-
-import org.jclouds.sqs.domain.Queue;
-
-import com.google.common.base.Function;
-
-/**
- * 
- * @author Adrian Cole
- */
-@Singleton
-public class QueueLocation implements Function<Object, URI> {
-
-   public URI apply(Object from) {
-      return ((Queue) from).getLocation();
-   }
-
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/options/CreateQueueOptions.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/options/CreateQueueOptions.java
deleted file mode 100644
index b881e5b..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/options/CreateQueueOptions.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.options;
-
-import org.jclouds.http.options.BaseHttpRequestOptions;
-
-/**
- * Contains options supported in the Form API for the CreateQueue operation. <h2>
- * Usage</h2> The recommended way to instantiate a CreateQueueOptions object is to statically import
- * CreateQueueOptions.Builder.* and invoke a static creation method followed by an instance mutator
- * (if needed):
- * <p/>
- * <code>
- * import static org.jclouds.sqs.options.CreateQueueOptions.Builder.*
- * <p/>
- * SQSClient connection = // get connection
- * Queue queue = connection.createQueueInRegion(defaultVisibilityTimeout("foo"));
- * <code>
- * 
- * @author Adrian Cole
- * @see <a
- *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryCreateQueue.html"
- *      />
- */
-public class CreateQueueOptions extends BaseHttpRequestOptions {
-
-   /**
-    * A default value for the queue's visibility timeout (30 seconds) is set when the queue is
-    * created. You can override this value with the DefaultVisibilityTimeout request parameter. For
-    * more information, see Visibility Timeout in the Amazon SQS Developer Guide.
-    * 
-    * @param seconds
-    *           The visibility timeout (in seconds) to use for this queue. 0 to 43200 (maximum 12
-    *           hours); Default: 30 seconds
-    */
-   public CreateQueueOptions defaultVisibilityTimeout(int seconds) {
-      //TODO validate
-      formParameters.put("DefaultVisibilityTimeout", seconds+"");
-      return this;
-   }
-
-   public String getRestorableBy() {
-      return getFirstFormOrNull("DefaultVisibilityTimeout");
-   }
-
-   public static class Builder {
-
-      /**
-       * @see CreateQueueOptions#defaultVisibilityTimeout(int )
-       */
-      public static CreateQueueOptions defaultVisibilityTimeout(int seconds) {
-         CreateQueueOptions options = new CreateQueueOptions();
-         return options.defaultVisibilityTimeout(seconds);
-      }
-
-   }
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/options/ListQueuesOptions.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/options/ListQueuesOptions.java
deleted file mode 100644
index e300419..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/options/ListQueuesOptions.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.options;
-
-import org.jclouds.http.options.BaseHttpRequestOptions;
-
-/**
- * Contains options supported in the Form API for the ListQueues operation. <h2>
- * Usage</h2> The recommended way to instantiate a ListQueuesOptions object is to statically import
- * ListQueuesOptions.Builder.* and invoke a static creation method followed by an instance mutator
- * (if needed):
- * <p/>
- * <code>
- * import static org.jclouds.sqs.options.ListQueuesOptions.Builder.*
- * <p/>
- * SQSClient connection = // get connection
- * Set<Queue> queues = connection.listQueuesInRegion(queuePrefix("foo"));
- * <code>
- * 
- * @author Adrian Cole
- * @see <a
- *      href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
- *      />
- */
-public class ListQueuesOptions extends BaseHttpRequestOptions {
-
-   /**
-    * String to use for filtering the list results. Only those queues whose name begins with the
-    * specified string are returned.
-    * 
-    * @param prefix
-    *           Maximum 80 characters; alphanumeric characters, hyphens (-), and underscores (_) are
-    *           allowed.
-    */
-   public ListQueuesOptions queuePrefix(String prefix) {
-      //TODO validate
-      formParameters.put("QueueNamePrefix", prefix);
-      return this;
-   }
-
-   public String getRestorableBy() {
-      return getFirstFormOrNull("QueueNamePrefix");
-   }
-
-   public static class Builder {
-
-      /**
-       * @see ListQueuesOptions#queuePrefix(String )
-       */
-      public static ListQueuesOptions queuePrefix(String prefix) {
-         ListQueuesOptions options = new ListQueuesOptions();
-         return options.queuePrefix(prefix);
-      }
-
-   }
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/package-info.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/package-info.java
deleted file mode 100644
index 630b1ed..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/package-info.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.
- */
-/**
- * This package contains an Amazon SQS client implemented by {@link org.jclouds.http.HttpCommandExecutorService} commands.
- *
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/index.html"/>
- * @author Adrian Cole
- */
-package org.jclouds.sqs;
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/reference/SQSParameters.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/reference/SQSParameters.java
deleted file mode 100644
index 6e2a491..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/reference/SQSParameters.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.reference;
-
-/**
- * Configuration properties and constants used in SQS connections.
- * 
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/2009-02-01/APIReference/Query_QueryParams.html"
- *      />
- * @author Adrian Cole
- */
-public interface SQSParameters {
-
-   /**
-    * The action to perform. For example: CreateQueue.
-    */
-   public static final String ACTION = "Action";
-
-   /**
-    * The API version to use, as specified in the WSDL. For example: 2009-02-01.
-    */
-   public static final String VERSION = "Version";
-
-   /**
-    * Your Access Key ID. For example: 0AS7253JW73RRM652K02. For more information, see Your AWS
-    * Identifiers in the Amazon SQS Developer Guide.
-    */
-   public static final String AWS_ACCESS_KEY_ID = "AWSAccessKeyId";
-
-   /**
-    * The date and time the request is signed, in the format YYYY-MM-DDThh:mm:ssZ, as specified in
-    * the ISO 8601 standard. Query requests must include either Timestamp or Expires, but not both.
-    * 
-    */
-   public static final String TIMESTAMP = "Timestamp";
-
-   /**
-    * The date and time at which the signature included in the request expires, in the format
-    * YYYY-MM-DDThh:mm:ssZ, as specified in the ISO 8601 standard. Query requests must include
-    * either Timestamp or Expires, but not both.
-    */
-   public static final String EXPIRES = "Expires";
-   /**
-    * A request signature (for information, see Request Authentication in the Amazon SQS Developer
-    * Guide). For example: Qnpl4Qk/7tINHzfXCiT7VbBatDA=.
-    */
-   public static final String SIGNATURE = "Signature";
-   /**
-    *Required when you use signature version 2 with Query requests. For more information, see Query
-    * Request Authentication in the Amazon SQS Developer Guide.
-    */
-   public static final String SIGNATURE_METHOD = "SignatureMethod";
-   /**
-    * For more information, see Query Request Authentication in the Amazon SQS Developer Guide.
-    */
-   public static final String SIGNATURE_VERSION = "SignatureVersion";
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/ListQueuesResponseHandler.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/ListQueuesResponseHandler.java
deleted file mode 100644
index 746d8fa..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/ListQueuesResponseHandler.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.xml;
-
-import java.util.Set;
-
-import javax.inject.Inject;
-
-import org.jclouds.sqs.domain.Queue;
-import org.jclouds.http.functions.ParseSax;
-
-import com.google.common.collect.Sets;
-
-/**
- * 
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
- *      />
- * @author Adrian Cole
- */
-public class ListQueuesResponseHandler extends ParseSax.HandlerWithResult<Set<Queue>> {
-
-   Set<Queue> queues = Sets.newLinkedHashSet();
-
-   private final QueueHandler qHandler;
-
-   @Inject
-   ListQueuesResponseHandler(QueueHandler qHandler) {
-      this.qHandler = qHandler;
-   }
-
-   public Set<Queue> getResult() {
-      return queues;
-   }
-
-   public void endElement(String uri, String name, String qName) {
-      qHandler.endElement(uri, name, qName);
-      if (qName.equals("QueueUrl")) {
-         queues.add(qHandler.getResult());
-      }
-   }
-
-   public void characters(char ch[], int start, int length) {
-      qHandler.characters(ch, start, length);
-   }
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/MD5Handler.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/MD5Handler.java
deleted file mode 100644
index f0d1f3e..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/MD5Handler.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.xml;
-
-import org.jclouds.crypto.CryptoStreams;
-import org.jclouds.http.functions.ParseSax;
-
-/**
- * 
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QuerySendMessage.html"
- *      />
- * @author Adrian Cole
- */
-public class MD5Handler extends ParseSax.HandlerWithResult<byte[]> {
-
-   private StringBuilder currentText = new StringBuilder();
-   byte[] md5;
-
-   public byte[] getResult() {
-      return md5;
-   }
-
-   public void endElement(String uri, String name, String qName) {
-      if (qName.equals("MD5OfMessageBody")) {
-         String md5Hex = currentText.toString().trim();
-         this.md5 = CryptoStreams.hex(md5Hex);
-      }
-      currentText = new StringBuilder();
-   }
-
-   public void characters(char ch[], int start, int length) {
-      currentText.append(ch, start, length);
-   }
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/QueueHandler.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/QueueHandler.java
deleted file mode 100644
index ae581c1..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/QueueHandler.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.xml;
-
-import java.net.URI;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Provider;
-import javax.ws.rs.core.UriBuilder;
-
-import org.jclouds.sqs.domain.Queue;
-import org.jclouds.http.functions.ParseSax;
-import org.jclouds.location.Region;
-
-import com.google.common.collect.ImmutableBiMap;
-
-/**
- * 
- * @see <a href=
- *      "http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
- *      />
- * @author Adrian Cole
- */
-public class QueueHandler extends ParseSax.HandlerWithResult<Queue> {
-
-   private StringBuilder currentText = new StringBuilder();
-   Queue queue;
-
-   private final ImmutableBiMap<URI, String> regionBiMap;
-   private final Provider<UriBuilder> uriBuilderProvider;
-
-   @Inject
-   QueueHandler(Provider<UriBuilder> uriBuilderProvider, @Region Map<String, URI> regionMap) {
-      this.uriBuilderProvider = uriBuilderProvider;
-      this.regionBiMap = ImmutableBiMap.<String, URI> copyOf(regionMap).inverse();
-   }
-
-   public Queue getResult() {
-      return queue;
-   }
-
-   public void endElement(String uri, String name, String qName) {
-
-      if (qName.equals("QueueUrl")) {
-         String uriText = currentText.toString().trim();
-         String queueName = uriText.substring(uriText.lastIndexOf('/') + 1);
-         URI location = URI.create(uriText);
-         URI regionURI = uriBuilderProvider.get().uri(location).replacePath("").build();
-         String region = regionBiMap.get(regionURI);
-         this.queue = new Queue(region, queueName, location);
-      }
-      currentText = new StringBuilder();
-   }
-
-   public void characters(char ch[], int start, int length) {
-      currentText.append(ch, start, length);
-   }
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexListQueuesResponseHandler.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexListQueuesResponseHandler.java
deleted file mode 100644
index dee858c..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexListQueuesResponseHandler.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.xml;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.Set;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import org.jclouds.sqs.domain.Queue;
-import org.jclouds.sqs.xml.internal.BaseRegexQueueHandler;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.functions.ReturnStringIf2xx;
-import org.jclouds.location.Region;
-
-import com.google.common.base.Function;
-
-/**
- * 
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
- *      />
- * @author Adrian Cole
- */
-@Singleton
-public class RegexListQueuesResponseHandler extends BaseRegexQueueHandler implements
-         Function<HttpResponse, Set<Queue>> {
-   private final ReturnStringIf2xx returnStringIf200;
-
-   @Inject
-   RegexListQueuesResponseHandler(@Region Map<String, URI> regionMap,
-            ReturnStringIf2xx returnStringIf200) {
-      super(regionMap);
-      this.returnStringIf200 = returnStringIf200;
-   }
-
-   @Override
-   public Set<Queue> apply(HttpResponse response) {
-      return parse(returnStringIf200.apply(response));
-   }
-
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexMD5Handler.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexMD5Handler.java
deleted file mode 100644
index a4317c2..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexMD5Handler.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.xml;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.inject.Inject;
-
-import org.jclouds.crypto.CryptoStreams;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.functions.ReturnStringIf2xx;
-
-import com.google.common.base.Function;
-import com.google.inject.Singleton;
-
-/**
- * 
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QuerySendMessage.html"
- *      />
- * @author Adrian Cole
- */
-@Singleton
-public class RegexMD5Handler implements Function<HttpResponse, byte[]> {
-   Pattern pattern = Pattern.compile("<MD5OfMessageBody>([\\S&&[^<]]+)</MD5OfMessageBody>");
-   private final ReturnStringIf2xx returnStringIf200;
-
-   @Inject
-   RegexMD5Handler(ReturnStringIf2xx returnStringIf200) {
-      this.returnStringIf200 = returnStringIf200;
-   }
-
-   @Override
-   public byte[] apply(HttpResponse response) {
-      byte[] value = null;
-      String content = returnStringIf200.apply(response);
-      if (content != null) {
-         Matcher matcher = pattern.matcher(content);
-         if (matcher.find()) {
-            value = CryptoStreams.hex(matcher.group(1));
-         }
-      }
-      return value;
-   }
-
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexQueueHandler.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexQueueHandler.java
deleted file mode 100644
index 086a053..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/RegexQueueHandler.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.xml;
-
-import java.net.URI;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import org.jclouds.sqs.domain.Queue;
-import org.jclouds.sqs.xml.internal.BaseRegexQueueHandler;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.functions.ReturnStringIf2xx;
-import org.jclouds.location.Region;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-
-/**
- * 
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
- *      />
- * @author Adrian Cole
- */
-@Singleton
-public class RegexQueueHandler extends BaseRegexQueueHandler implements
-         Function<HttpResponse, Queue> {
-   private final ReturnStringIf2xx returnStringIf200;
-
-   @Inject
-   RegexQueueHandler(@Region Map<String, URI> regionMap, ReturnStringIf2xx returnStringIf200) {
-      super(regionMap);
-      this.returnStringIf200 = returnStringIf200;
-   }
-
-   @Override
-   public Queue apply(HttpResponse response) {
-      return Iterables.getOnlyElement(parse(returnStringIf200.apply(response)));
-   }
-}
diff --git a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java b/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java
deleted file mode 100644
index 8f71228..0000000
--- a/sandbox-apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.xml.internal;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import org.jclouds.sqs.domain.Queue;
-
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.Sets;
-
-/**
- * 
- * @see <a href="http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Query_QueryListQueues.html"
- *      />
- * @author Adrian Cole
- */
-@Singleton
-public class BaseRegexQueueHandler {
-   private final ImmutableBiMap<URI, String> uriToRegion;
-   Pattern pattern = Pattern.compile("<QueueUrl>(https://[\\S&&[^<]]+)</QueueUrl>");
-
-   @Inject
-   protected BaseRegexQueueHandler(Map<String, URI> regionMap) {
-      this.uriToRegion = ImmutableBiMap.<String, URI> builder().putAll(regionMap).build().inverse();
-   }
-
-   public Set<Queue> parse(String in) {
-      Set<Queue> queues = Sets.newLinkedHashSet();
-      Matcher matcher = pattern.matcher(in);
-      while (matcher.find()) {
-         String uriText = matcher.group(1);
-         String queueName = uriText.substring(uriText.lastIndexOf('/') + 1);
-         URI location = URI.create(uriText);
-         String regionString = uriText.substring(0, uriText.indexOf(".com/") + 4);
-         URI regionURI = URI.create(regionString);
-         String region = uriToRegion.get(regionURI);
-         queues.add(new Queue(region, queueName, location));
-      }
-      return queues;
-   }
-
-}
diff --git a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/SQSAsyncClientTest.java b/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/SQSAsyncClientTest.java
deleted file mode 100644
index 9659b63..0000000
--- a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/SQSAsyncClientTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs;
-
-import static org.testng.Assert.assertEquals;
-
-import java.io.IOException;
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.util.Properties;
-
-import javax.inject.Named;
-
-import org.jclouds.Constants;
-import org.jclouds.aws.filters.FormSigner;
-import org.jclouds.date.DateService;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.RequiresHttp;
-import org.jclouds.rest.ConfiguresRestClient;
-import org.jclouds.rest.RestClientTest;
-import org.jclouds.rest.RestContextFactory;
-import org.jclouds.rest.RestContextSpec;
-import org.jclouds.rest.internal.RestAnnotationProcessor;
-import org.jclouds.sqs.config.SQSRestClientModule;
-import org.jclouds.sqs.options.CreateQueueOptions;
-import org.jclouds.sqs.options.ListQueuesOptions;
-import org.jclouds.sqs.xml.RegexListQueuesResponseHandler;
-import org.jclouds.sqs.xml.RegexQueueHandler;
-import org.testng.annotations.Test;
-
-import com.google.inject.Module;
-import com.google.inject.TypeLiteral;
-
-/**
- * Tests behavior of {@code SQSAsyncClient}
- * 
- * @author Adrian Cole
- */
-// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
-@Test(groups = "unit", testName = "SQSAsyncClientTest")
-public class SQSAsyncClientTest extends RestClientTest<SQSAsyncClient> {
-
-   @RequiresHttp
-   @ConfiguresRestClient
-   private static final class TestSQSRestClientModule extends SQSRestClientModule {
-
-      @Override
-      protected String provideTimeStamp(final DateService dateService,
-            @Named(Constants.PROPERTY_SESSION_INTERVAL) int expiration) {
-         return "2009-11-08T15:54:08.897Z";
-      }
-   }
-
-   public void testListQueuesInRegion() throws SecurityException, NoSuchMethodException, IOException {
-      Method method = SQSAsyncClient.class.getMethod("listQueuesInRegion", String.class,
-            Array.newInstance(ListQueuesOptions.class, 0).getClass());
-      HttpRequest request = processor.createRequest(method, (String) null);
-
-      assertRequestLineEquals(request, "POST https://sqs.us-east-1.amazonaws.com/ HTTP/1.1");
-      assertNonPayloadHeadersEqual(request, "Host: sqs.us-east-1.amazonaws.com\n");
-      assertPayloadEquals(request, "Version=2009-02-01&Action=ListQueues", "application/x-www-form-urlencoded", false);
-
-      assertResponseParserClassEquals(method, request, RegexListQueuesResponseHandler.class);
-      assertSaxResponseParserClassEquals(method, null);
-      assertExceptionParserClassEquals(method, null);
-
-      checkFilters(request);
-   }
-
-   public void testListQueuesInRegionOptions() throws SecurityException, NoSuchMethodException, IOException {
-      Method method = SQSAsyncClient.class.getMethod("listQueuesInRegion", String.class,
-            Array.newInstance(ListQueuesOptions.class, 0).getClass());
-      HttpRequest request = processor.createRequest(method, null, ListQueuesOptions.Builder.queuePrefix("prefix"));
-
-      assertRequestLineEquals(request, "POST https://sqs.us-east-1.amazonaws.com/ HTTP/1.1");
-      assertNonPayloadHeadersEqual(request, "Host: sqs.us-east-1.amazonaws.com\n");
-      assertPayloadEquals(request, "Version=2009-02-01&Action=ListQueues&QueueNamePrefix=prefix",
-            "application/x-www-form-urlencoded", false);
-
-      assertResponseParserClassEquals(method, request, RegexListQueuesResponseHandler.class);
-      assertSaxResponseParserClassEquals(method, null);
-      assertExceptionParserClassEquals(method, null);
-
-      checkFilters(request);
-   }
-
-   public void testCreateQueueInRegion() throws SecurityException, NoSuchMethodException, IOException {
-      Method method = SQSAsyncClient.class.getMethod("createQueueInRegion", String.class, String.class, Array
-            .newInstance(CreateQueueOptions.class, 0).getClass());
-      HttpRequest request = processor.createRequest(method, null, "queueName");
-
-      assertRequestLineEquals(request, "POST https://sqs.us-east-1.amazonaws.com/ HTTP/1.1");
-      assertNonPayloadHeadersEqual(request, "Host: sqs.us-east-1.amazonaws.com\n");
-      assertPayloadEquals(request, "Version=2009-02-01&Action=CreateQueue&QueueName=queueName",
-            "application/x-www-form-urlencoded", false);
-
-      assertResponseParserClassEquals(method, request, RegexQueueHandler.class);
-      assertSaxResponseParserClassEquals(method, null);
-      assertExceptionParserClassEquals(method, null);
-
-      checkFilters(request);
-   }
-
-   public void testCreateQueueInRegionOptions() throws SecurityException, NoSuchMethodException, IOException {
-      Method method = SQSAsyncClient.class.getMethod("createQueueInRegion", String.class, String.class, Array
-            .newInstance(CreateQueueOptions.class, 0).getClass());
-      HttpRequest request = processor.createRequest(method, null, "queueName",
-            CreateQueueOptions.Builder.defaultVisibilityTimeout(45));
-
-      assertRequestLineEquals(request, "POST https://sqs.us-east-1.amazonaws.com/ HTTP/1.1");
-      assertNonPayloadHeadersEqual(request, "Host: sqs.us-east-1.amazonaws.com\n");
-      assertPayloadEquals(request,
-            "Version=2009-02-01&Action=CreateQueue&QueueName=queueName&DefaultVisibilityTimeout=45",
-            "application/x-www-form-urlencoded", false);
-
-      assertResponseParserClassEquals(method, request, RegexQueueHandler.class);
-      assertSaxResponseParserClassEquals(method, null);
-      assertExceptionParserClassEquals(method, null);
-
-      checkFilters(request);
-   }
-
-   @Override
-   protected void checkFilters(HttpRequest request) {
-      assertEquals(request.getFilters().size(), 1);
-      assertEquals(request.getFilters().get(0).getClass(), FormSigner.class);
-   }
-
-   @Override
-   protected TypeLiteral<RestAnnotationProcessor<SQSAsyncClient>> createTypeLiteral() {
-      return new TypeLiteral<RestAnnotationProcessor<SQSAsyncClient>>() {
-      };
-   }
-
-   @Override
-   protected Module createModule() {
-      return new TestSQSRestClientModule();
-   }
-
-   protected String provider = "sqs";
-
-   @Override
-   protected Properties getProperties() {
-      Properties overrides = new Properties();
-      overrides.setProperty(provider + ".endpoint", "https://sqs.us-east-1.amazonaws.com");
-      overrides.setProperty(provider + ".propertiesbuilder", SQSPropertiesBuilder.class.getName());
-      overrides.setProperty(provider + ".contextbuilder", SQSContextBuilder.class.getName());
-      return overrides;
-   }
-
-   @Override
-   public RestContextSpec<?, ?> createContextSpec() {
-      return new RestContextFactory(getProperties()).createContextSpec(provider, "identity", "credential",
-            new Properties());
-   }
-
-}
diff --git a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/SQSClientLiveTest.java b/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/SQSClientLiveTest.java
deleted file mode 100644
index 2ebff95..0000000
--- a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/SQSClientLiveTest.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.jclouds.sqs.options.ListQueuesOptions.Builder.queuePrefix;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-
-import java.io.IOException;
-import java.util.Properties;
-import java.util.Set;
-import java.util.SortedSet;
-
-import org.jclouds.Constants;
-import org.jclouds.aws.AWSResponseException;
-import org.jclouds.crypto.CryptoStreams;
-import org.jclouds.logging.log4j.config.Log4JLoggingModule;
-import org.jclouds.rest.RestContext;
-import org.jclouds.rest.RestContextFactory;
-import org.jclouds.sqs.domain.Queue;
-import org.testng.annotations.AfterTest;
-import org.testng.annotations.BeforeGroups;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import com.google.inject.Module;
-
-/**
- * Tests behavior of {@code SQSClient}
- * 
- * @author Adrian Cole
- */
-@Test(groups = "live", sequential = true)
-public class SQSClientLiveTest {
-
-   private SQSClient client;
-
-   private RestContext<SQSClient, SQSAsyncClient> context;
-
-   private Set<Queue> queues = Sets.newHashSet();
-   protected String provider = "sqs";
-   protected String identity;
-   protected String credential;
-   protected String endpoint;
-   protected String apiVersion;
-
-   protected void setupCredentials() {
-      identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity");
-      credential = checkNotNull(System.getProperty("test." + provider + ".credential"), "test." + provider
-            + ".credential");
-      endpoint = System.getProperty("test." + provider + ".endpoint");
-     apiVersion = System.getProperty("test." + provider + ".api-version");
-   }
-
-   protected Properties setupProperties() {
-      Properties overrides = new Properties();
-      overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true");
-      overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true");
-      overrides.setProperty(provider + ".identity", identity);
-      if (credential != null)
-         overrides.setProperty(provider + ".credential", credential);
-      if (endpoint != null)
-         overrides.setProperty(provider + ".endpoint", endpoint);
-      if (apiVersion != null)
-         overrides.setProperty(provider + ".api-version", apiVersion);
-      return overrides;
-   }
-
-   @BeforeGroups(groups = { "live" })
-   public void setupClient() {
-      setupCredentials();
-      Properties overrides = setupProperties();
-      context = new RestContextFactory().createContext(provider, ImmutableSet.<Module> of(new Log4JLoggingModule()),
-            overrides);
-      this.client = context.getApi();
-   }
-
-   @Test
-   protected void testListQueues() throws InterruptedException {
-      listQueuesInRegion(null);
-   }
-
-   protected void listQueuesInRegion(String region) throws InterruptedException {
-      SortedSet<Queue> allResults = Sets.newTreeSet(client.listQueuesInRegion(region));
-      assertNotNull(allResults);
-      if (allResults.size() >= 1) {
-         Queue queue = allResults.last();
-         assertQueueInList(region, queue);
-      }
-   }
-
-   public static final String PREFIX = System.getProperty("user.name") + "-sqs";
-
-   @Test
-   protected void testCreateQueue() throws InterruptedException {
-      createQueueInRegion(null, PREFIX + "1");
-   }
-
-   public String createQueueInRegion(final String region, String queueName) throws InterruptedException {
-      try {
-         SortedSet<Queue> result = Sets.newTreeSet(client.listQueuesInRegion(region, queuePrefix(queueName)));
-         if (result.size() >= 1) {
-            client.deleteQueue(result.last());
-            queueName += 1;// cannot recreate a queue within 60 seconds
-         }
-      } catch (Exception e) {
-
-      }
-      Queue queue = null;
-      int tries = 0;
-      while (queue == null && tries < 5) {
-         try {
-            tries++;
-            queue = client.createQueueInRegion(region, queueName);
-         } catch (AWSResponseException e) {
-            queueName += "1";
-            if (e.getError().getCode().equals("AWS.SimpleQueueService.QueueDeletedRecently"))// TODO
-               // retry
-               // handler
-               continue;
-            throw e;
-         }
-      }
-      if (region != null)
-         assertEquals(queue.getRegion(), region);
-      assertEquals(queue.getName(), queueName);
-      assertQueueInList(region, queue);
-      queues.add(queue);
-      return queueName;
-   }
-
-   @Test(dependsOnMethods = "testCreateQueue")
-   protected void testSendMessage() throws InterruptedException, IOException {
-      String message = "hardyharhar";
-      byte[] md5 = CryptoStreams.md5(message.getBytes());
-      for (Queue queue : queues) {
-         assertEquals(client.sendMessage(queue, message), md5);
-      }
-   }
-
-   private void assertQueueInList(final String region, Queue queue) throws InterruptedException {
-      final Queue finalQ = queue;
-      assertEventually(new Runnable() {
-         public void run() {
-            SortedSet<Queue> result = Sets.newTreeSet(client.listQueuesInRegion(region, queuePrefix(finalQ.getName())));
-            assertNotNull(result);
-            assert result.size() >= 1 : result;
-            assertEquals(result.first(), finalQ);
-         }
-      });
-   }
-
-   private static final int INCONSISTENCY_WINDOW = 10000;
-
-   /**
-    * Due to eventual consistency, container commands may not return correctly immediately. Hence,
-    * we will try up to the inconsistency window to see if the assertion completes.
-    */
-   protected static void assertEventually(Runnable assertion) throws InterruptedException {
-      long start = System.currentTimeMillis();
-      AssertionError error = null;
-      for (int i = 0; i < 30; i++) {
-         try {
-            assertion.run();
-            if (i > 0)
-               System.err.printf("%d attempts and %dms asserting %s%n", i + 1, System.currentTimeMillis() - start,
-                     assertion.getClass().getSimpleName());
-            return;
-         } catch (AssertionError e) {
-            error = e;
-         }
-         Thread.sleep(INCONSISTENCY_WINDOW / 30);
-      }
-      if (error != null)
-         throw error;
-   }
-
-   @AfterTest
-   public void shutdown() {
-      context.close();
-   }
-}
diff --git a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/options/CreateQueueOptionsTest.java b/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/options/CreateQueueOptionsTest.java
deleted file mode 100644
index 1445bc2..0000000
--- a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/options/CreateQueueOptionsTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.options;
-
-import static org.jclouds.sqs.options.CreateQueueOptions.Builder.defaultVisibilityTimeout;
-import static org.testng.Assert.assertEquals;
-
-import java.util.Collections;
-
-import org.jclouds.http.options.HttpRequestOptions;
-import org.testng.annotations.Test;
-
-/**
- * Tests possible uses of CreateQueueOptions and CreateQueueOptions.Builder.*
- * 
- * @author Adrian Cole
- */
-public class CreateQueueOptionsTest {
-
-   @Test
-   public void testAssignability() {
-      assert HttpRequestOptions.class.isAssignableFrom(CreateQueueOptions.class);
-      assert !String.class.isAssignableFrom(CreateQueueOptions.class);
-   }
-
-   @Test
-   public void testTimeout() {
-      CreateQueueOptions options = new CreateQueueOptions();
-      options.defaultVisibilityTimeout(1);
-      assertEquals(options.buildFormParameters().get("DefaultVisibilityTimeout"), Collections
-               .singletonList("1"));
-   }
-
-   @Test
-   public void testNullTimeout() {
-      CreateQueueOptions options = new CreateQueueOptions();
-      assertEquals(options.buildFormParameters().get("DefaultVisibilityTimeout"), Collections.EMPTY_LIST);
-   }
-
-   @Test
-   public void testTimeoutStatic() {
-      CreateQueueOptions options = defaultVisibilityTimeout(1);
-      assertEquals(options.buildFormParameters().get("DefaultVisibilityTimeout"), Collections
-               .singletonList("1"));
-   }
-
-   public void testNoTimeout() {
-      defaultVisibilityTimeout(0);
-   }
-}
diff --git a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/xml/ListQueuesResponseHandlerTest.java b/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/xml/ListQueuesResponseHandlerTest.java
deleted file mode 100644
index 729333f..0000000
--- a/sandbox-apis/sqs/src/test/java/org/jclouds/sqs/xml/ListQueuesResponseHandlerTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
- * Licensed to jclouds, Inc. (jclouds) under one or more
- * contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  jclouds licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy 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.sqs.xml;
-
-import static org.testng.Assert.assertEquals;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.inject.Singleton;
-import javax.ws.rs.core.UriBuilder;
-
-import org.jclouds.PerformanceTest;
-import org.jclouds.aws.domain.Region;
-import org.jclouds.http.HttpResponse;
-import org.jclouds.http.functions.ParseSax;
-import org.jclouds.http.functions.ParseSax.Factory;
-import org.jclouds.http.functions.config.SaxParserModule;
-import org.jclouds.io.Payloads;
-import org.jclouds.sqs.domain.Queue;
-import org.testng.annotations.BeforeTest;
-import org.testng.annotations.Test;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.InputSupplier;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-import com.google.inject.Provides;
-import com.sun.jersey.api.uri.UriBuilderImpl;
-
-/**
- * Tests behavior of {@code ListQueuesResponseHandlerr}
- * 
- * @author Adrian Cole
- */
-// NOTE:without testName, this will fail w/NPE during surefire
-@Test(groups = "performance", sequential = true, timeOut = 2 * 60 * 1000, testName = "ListQueuesResponseHandlerTest")
-public class ListQueuesResponseHandlerTest extends PerformanceTest {
-
-   private Injector injector;
-   private Factory factory;
-   private RegexListQueuesResponseHandler handler;
-   private InputSupplier<ByteArrayInputStream> supplier;
-
-   @BeforeTest
-   protected void setUpInjector() throws IOException {
-
-      LOOP_COUNT = 100000;
-      THREAD_COUNT = 100;
-
-      System.out.printf("queue response handle speed test %d threads %d count%n", THREAD_COUNT,
-               LOOP_COUNT);
-      injector = Guice.createInjector(new SaxParserModule(), new AbstractModule() {
-
-         @Override
-         protected void configure() {
-            bind(UriBuilder.class).to(UriBuilderImpl.class);
-         }
-
-         @SuppressWarnings("unused")
-         @Provides
-         @Singleton
-         @org.jclouds.location.Region
-         Map<String, URI> provideRegions() {
-            return ImmutableMap.<String, URI> of(Region.EU_WEST_1, URI
-                     .create("https://eu-west-1.queue.amazonaws.com"));
-         }
-
-      });
-      handler = injector.getInstance(RegexListQueuesResponseHandler.class);
-
-      factory = injector.getInstance(ParseSax.Factory.class);
-      InputStream inputStream = getClass().getResourceAsStream("/list_queues.xml");
-      ByteArrayOutputStream out = new ByteArrayOutputStream();
-      ByteStreams.copy(inputStream, out);
-      supplier = ByteStreams.newInputStreamSupplier(out.toByteArray());
-      assert factory != null;
-   }
-
-   Set<Queue> expected = ImmutableSet.of(new Queue(Region.EU_WEST_1, "adriancole-sqs1", URI
-            .create("https://eu-west-1.queue.amazonaws.com/993194456877/adriancole-sqs1")),
-
-   new Queue(Region.EU_WEST_1, "adriancole-sqs111", URI
-            .create("https://eu-west-1.queue.amazonaws.com/993194456877/adriancole-sqs111")));
-
-   public void testSax() {
-      ListQueuesResponseHandler handler = injector.getInstance(ListQueuesResponseHandler.class);
-      Set<Queue> result;
-      try {
-         result = factory.create(handler).parse(supplier.getInput());
-         assertEquals(result, expected);
-      } catch (Exception e) {
-         Throwables.propagate(e);
-      }
-   }
-
-   public void testRegex() {
-      try {
-         assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newPayload(supplier
-                  .getInput()))), expected);
-      } catch (IOException e) {
-         Throwables.propagate(e);
-      }
-   }
-
-   @Test(enabled = false)
-   void testRegexSerialResponseTime() throws IOException {
-      long now = System.currentTimeMillis();
-      for (int i = 0; i < LOOP_COUNT; i++)
-         testRegex();
-      System.out.println("testRegex serial: " + (System.currentTimeMillis() - now) + "");
-   }
-
-   @Test(enabled = false)
-   void testRegexParallelResponseTime() throws Throwable {
-      List<Runnable> tasks = ImmutableList.<Runnable> of(new Runnable() {
-         public void run() {
-            testRegex();
-         }
-      });
-      executeMultiThreadedPerformanceTest("testRegexParallelResponseTime", tasks);
-   }
-
-   @Test(enabled = false)
-   void testSaxSerialResponseTime() throws IOException {
-      long now = System.currentTimeMillis();
-      for (int i = 0; i < LOOP_COUNT; i++)
-         testSax();
-      System.out.println("testSax serial: " + (System.currentTimeMillis() - now) + "");
-   }
-
-   @Test(enabled = false)
-   void testSaxParallelResponseTime() throws Throwable {
-      List<Runnable> tasks = ImmutableList.<Runnable> of(new Runnable() {
-         public void run() {
-            testSax();
-         }
-      });
-      executeMultiThreadedPerformanceTest("testSaxParallelResponseTime", tasks);
-   }
-
-}
diff --git a/sandbox-apis/sqs/src/test/resources/list_queues.xml b/sandbox-apis/sqs/src/test/resources/list_queues.xml
deleted file mode 100644
index ae5e35c..0000000
--- a/sandbox-apis/sqs/src/test/resources/list_queues.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0"?>
-<ListQueuesResponse xmlns="http://queue.amazonaws.com/doc/2009-02-01/"><ListQueuesResult><QueueUrl>https://eu-west-1.queue.amazonaws.com/993194456877/adriancole-sqs1</QueueUrl><QueueUrl>https://eu-west-1.queue.amazonaws.com/993194456877/adriancole-sqs111</QueueUrl></ListQueuesResult><ResponseMetadata><RequestId>313c81c8-e345-4c75-ad57-ce4d9d5ff35a</RequestId></ResponseMetadata></ListQueuesResponse>
\ No newline at end of file