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

git commit: JCLOUDS-146: Refactored asynchronous tasks in Abiquo

Updated Branches:
  refs/heads/master c5e108a83 -> 726b1f3ee


JCLOUDS-146: Refactored asynchronous tasks in Abiquo

Refactored asynchronous tasks to be generic, and created a
concrete task class for each existing task type. This way all
operations will produce a typed task, and operating with it
will be easier. This will also allow to get the results produced
by the task.


Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/commit/726b1f3e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/tree/726b1f3e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/diff/726b1f3e

Branch: refs/heads/master
Commit: 726b1f3ee39c7bbe29aad9830c55b2ef0a9b57cf
Parents: c5e108a
Author: Ignasi Barrera <ig...@gmail.com>
Authored: Wed Jul 3 09:39:38 2013 +0200
Committer: Ignasi Barrera <ig...@gmail.com>
Committed: Sat Jul 6 10:13:48 2013 +0200

----------------------------------------------------------------------
 .../strategy/AbiquoComputeServiceAdapter.java   |  3 +-
 .../abiquo/domain/DomainWithTasksWrapper.java   | 15 ++--
 .../jclouds/abiquo/domain/DomainWrapper.java    | 66 +++++++++++++--
 .../jclouds/abiquo/domain/cloud/Conversion.java |  4 +-
 .../abiquo/domain/cloud/VirtualAppliance.java   | 16 ++--
 .../abiquo/domain/cloud/VirtualMachine.java     | 88 ++++++++++++--------
 .../domain/cloud/VirtualMachineTemplate.java    | 27 +++---
 .../org/jclouds/abiquo/domain/cloud/Volume.java |  9 +-
 .../jclouds/abiquo/domain/config/Privilege.java |  1 -
 .../jclouds/abiquo/domain/task/AsyncTask.java   | 51 +++++++++++-
 .../abiquo/domain/task/ConversionTask.java      | 44 ++++++++++
 .../abiquo/domain/task/VirtualMachineTask.java  | 44 ++++++++++
 .../domain/task/VirtualMachineTemplateTask.java | 44 ++++++++++
 .../org/jclouds/abiquo/features/CloudApi.java   | 22 +++++
 .../abiquo/monitor/AsyncTaskMonitor.java        |  8 +-
 .../functions/AsyncTaskStatusMonitor.java       |  4 +-
 .../monitor/internal/BaseAsyncTaskMonitor.java  |  8 +-
 .../abiquo/reference/rest/ParentLinkName.java   |  2 +
 .../domain/cloud/VirtualApplianceLiveTest.java  |  6 +-
 .../domain/cloud/VirtualMachineLiveApiTest.java |  5 +-
 .../domain/cloud/VirtualMachineLiveTest.java    | 14 ++--
 .../VirtualMachineNetworkingLiveApiTest.java    | 20 ++---
 .../cloud/VirtualMachineStorageLiveApiTest.java | 10 +--
 .../abiquo/domain/cloud/VolumeLiveApiTest.java  |  4 +-
 .../abiquo/features/CloudApiExpectTest.java     | 78 +++++++++++++++++
 .../jclouds/abiquo/features/CloudApiTest.java   |  1 -
 .../features/InfrastructureApiExpectTest.java   |  2 +-
 .../functions/AsyncTaskStatusMonitorTest.java   |  7 +-
 .../resources/payloads/vm-accepted-request.xml  |  4 +
 .../src/test/resources/payloads/vm-snapshot.xml |  4 +
 30 files changed, 485 insertions(+), 126 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceAdapter.java b/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceAdapter.java
index 92cee74..2853f75 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceAdapter.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/compute/strategy/AbiquoComputeServiceAdapter.java
@@ -39,6 +39,7 @@ import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
 import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplateInVirtualDatacenter;
 import org.jclouds.abiquo.domain.enterprise.Enterprise;
 import org.jclouds.abiquo.domain.infrastructure.Datacenter;
+import org.jclouds.abiquo.domain.network.Ip;
 import org.jclouds.abiquo.domain.network.PublicIp;
 import org.jclouds.abiquo.features.services.AdministrationService;
 import org.jclouds.abiquo.features.services.CloudService;
@@ -150,7 +151,7 @@ public class AbiquoComputeServiceAdapter
       // private VLAN for the virtual datacenter
       PublicIp publicIp = find(vdc.listPurchasedPublicIps(), IpPredicates.<PublicIp> notUsed(), null);
       if (publicIp != null) {
-         List<PublicIp> ips = Lists.newArrayList();
+         List<Ip<?, ?>> ips = Lists.newArrayList();
          ips.add(publicIp);
          vm.setNics(ips);
       }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithTasksWrapper.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithTasksWrapper.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithTasksWrapper.java
index 5f6ddec..741a87d 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithTasksWrapper.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWithTasksWrapper.java
@@ -26,6 +26,8 @@ import org.jclouds.rest.ApiContext;
 import com.abiquo.model.transport.SingleResourceTransportDto;
 import com.abiquo.server.core.task.TaskDto;
 import com.abiquo.server.core.task.TasksDto;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
 import com.google.common.primitives.Longs;
 
@@ -41,18 +43,21 @@ public abstract class DomainWithTasksWrapper<T extends SingleResourceTransportDt
       super(context, target);
    }
 
-   public List<AsyncTask> listTasks() {
+   public List<AsyncTask<?, ?>> listTasks() {
       TasksDto result = context.getApi().getTaskApi().listTasks(target);
-      List<AsyncTask> tasks = wrap(context, AsyncTask.class, result.getCollection());
+      List<AsyncTask<?, ?>> tasks = Lists.newArrayList();
+      for (TaskDto dto : result.getCollection()) {
+         tasks.add(newTask(context, dto));
+      }
 
       // Return the most recent task first
-      Collections.sort(tasks, new Ordering<AsyncTask>() {
+      Collections.sort(tasks, new Ordering<AsyncTask<?, ?>>() {
          @Override
-         public int compare(final AsyncTask left, final AsyncTask right) {
+         public int compare(final AsyncTask<?, ?> left, final AsyncTask<?, ?> right) {
             return Longs.compare(left.getTimestamp(), right.getTimestamp());
          }
       }.reverse());
 
-      return tasks;
+      return ImmutableList.copyOf(tasks);
    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWrapper.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWrapper.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWrapper.java
index 1fe0719..4e3e728 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWrapper.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/DomainWrapper.java
@@ -29,6 +29,9 @@ import java.util.List;
 import org.jclouds.abiquo.AbiquoApi;
 import org.jclouds.abiquo.domain.exception.WrapperException;
 import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.domain.task.ConversionTask;
+import org.jclouds.abiquo.domain.task.VirtualMachineTask;
+import org.jclouds.abiquo.domain.task.VirtualMachineTemplateTask;
 import org.jclouds.abiquo.domain.util.LinkUtils;
 import org.jclouds.abiquo.reference.ValidationErrors;
 import org.jclouds.http.HttpResponse;
@@ -40,6 +43,7 @@ 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.abiquo.server.core.task.enums.TaskType;
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
@@ -199,13 +203,13 @@ public abstract class DomainWrapper<T extends SingleResourceTransportDto> {
     *           The accepted request dto.
     * @return The async task.
     */
-   protected AsyncTask getTask(final AcceptedRequestDto<String> acceptedRequest) {
+   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);
+      TaskDto dto = context.getApi().getTaskApi().getTask(taskLink);
+      return newTask(context, dto);
    }
 
    /**
@@ -216,19 +220,63 @@ public abstract class DomainWrapper<T extends SingleResourceTransportDto> {
     *           The accepted request dto.
     * @return The async task array.
     */
-   protected AsyncTask[] getTasks(final AcceptedRequestDto<String> acceptedRequest) {
-      List<AsyncTask> tasks = Lists.newArrayList();
+   protected AsyncTask<?, ?>[] getTasks(final AcceptedRequestDto<String> acceptedRequest) {
+      List<AsyncTask<?, ?>> tasks = Lists.newArrayList();
 
       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));
+         TaskDto dto = context.getApi().getTaskApi().getTask(link);
+         if (dto != null) {
+            tasks.add(newTask(context, dto));
          }
       }
 
-      AsyncTask[] taskArr = new AsyncTask[tasks.size()];
+      AsyncTask<?, ?>[] taskArr = new AsyncTask<?, ?>[tasks.size()];
       return tasks.toArray(taskArr);
    }
 
+   /**
+    * Creates a new {@link AsyncTask} for the given {@link TaskDto} and the
+    * given result class.
+    * 
+    * @param context
+    *           The API context.
+    * @param dto
+    *           The dto used to generate the domain object.
+    * @return The task domain object.
+    */
+   protected static AsyncTask<?, ?> newTask(final ApiContext<AbiquoApi> context, final TaskDto dto) {
+      // Can be null in untrackable tasks
+      if (dto == null) {
+         return null;
+      }
+
+      Class<? extends AsyncTask<?, ?>> taskClass = null;
+
+      switch (dto.getType().getOwnerType()) {
+         case CONVERSION:
+            taskClass = ConversionTask.class;
+            break;
+         case VIRTUAL_MACHINE_TEMPLATE:
+            taskClass = VirtualMachineTemplateTask.class;
+            break;
+         case VIRTUAL_MACHINE:
+            // A VirtualMachine task can generate a template (if task is an
+            // instance)
+            taskClass = dto.getType() == TaskType.INSTANCE || dto.getType() == TaskType.INSTANCE_PERSISTENT ? VirtualMachineTemplateTask.class
+                  : VirtualMachineTask.class;
+            break;
+      }
+
+      try {
+         Invokable<? extends AsyncTask<?, ?>, ? extends AsyncTask<?, ?>> cons = constructor(taskClass,
+               ApiContext.class, dto.getClass());
+         return cons.invoke(null, context, dto);
+      } catch (InvocationTargetException e) {
+         throw new WrapperException(taskClass, dto, e.getTargetException());
+      } catch (IllegalAccessException e) {
+         throw new WrapperException(taskClass, dto, e);
+      }
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Conversion.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Conversion.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Conversion.java
index 342cb59..5731a52 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Conversion.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Conversion.java
@@ -22,7 +22,7 @@ import java.util.Date;
 
 import org.jclouds.abiquo.AbiquoApi;
 import org.jclouds.abiquo.domain.DomainWithTasksWrapper;
-import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.domain.task.ConversionTask;
 import org.jclouds.abiquo.reference.ValidationErrors;
 import org.jclouds.abiquo.reference.rest.ParentLinkName;
 import org.jclouds.http.HttpResponse;
@@ -82,7 +82,7 @@ public class Conversion extends DomainWithTasksWrapper<ConversionDto> {
     *      ConversionResource- UpdateConversion</a>
     * @return The task reference to track its progress
     */
-   public AsyncTask restartFailedConversion() {
+   public ConversionTask restartFailedConversion() {
       return getVirtualMachineTemplate().requestConversion(getTargetFormat());
    }
 

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualAppliance.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualAppliance.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualAppliance.java
index fb9aa3d..e37b456 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualAppliance.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualAppliance.java
@@ -18,6 +18,7 @@ package org.jclouds.abiquo.domain.cloud;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import java.util.Arrays;
 import java.util.List;
 
 import org.jclouds.abiquo.AbiquoApi;
@@ -25,6 +26,7 @@ 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.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.reference.ValidationErrors;
 import org.jclouds.abiquo.reference.rest.ParentLinkName;
 import org.jclouds.rest.ApiContext;
@@ -185,7 +187,7 @@ public class VirtualAppliance extends DomainWrapper<VirtualApplianceDto> {
     * @return The list of tasks corresponding to the deploy process of each
     *         virtual machine in the appliance.
     */
-   public AsyncTask[] deploy() {
+   public VirtualMachineTask[] deploy() {
       return deploy(false);
    }
 
@@ -203,13 +205,14 @@ public class VirtualAppliance extends DomainWrapper<VirtualApplianceDto> {
     * @return The list of tasks corresponding to the deploy process of each
     *         virtual machine in the appliance.
     */
-   public AsyncTask[] deploy(final boolean forceEnterpriseSoftLimits) {
+   public VirtualMachineTask[] deploy(final boolean forceEnterpriseSoftLimits) {
       VirtualMachineTaskDto force = new VirtualMachineTaskDto();
       force.setForceEnterpriseSoftLimits(forceEnterpriseSoftLimits);
 
       AcceptedRequestDto<String> response = context.getApi().getCloudApi().deployVirtualAppliance(unwrap(), force);
 
-      return getTasks(response);
+      AsyncTask<?, ?>[] tasks = getTasks(response);
+      return Arrays.copyOf(tasks, tasks.length, VirtualMachineTask[].class);
    }
 
    /**
@@ -223,7 +226,7 @@ public class VirtualAppliance extends DomainWrapper<VirtualApplianceDto> {
     * @return The list of tasks corresponding to the undeploy process of each
     *         virtual machine in the appliance.
     */
-   public AsyncTask[] undeploy() {
+   public VirtualMachineTask[] undeploy() {
       return undeploy(false);
    }
 
@@ -241,13 +244,14 @@ public class VirtualAppliance extends DomainWrapper<VirtualApplianceDto> {
     * @return The list of tasks corresponding to the undeploy process of each
     *         virtual machine in the appliance.
     */
-   public AsyncTask[] undeploy(final boolean forceUndeploy) {
+   public VirtualMachineTask[] undeploy(final boolean forceUndeploy) {
       VirtualMachineTaskDto force = new VirtualMachineTaskDto();
       force.setForceUndeploy(forceUndeploy);
 
       AcceptedRequestDto<String> response = context.getApi().getCloudApi().undeployVirtualAppliance(unwrap(), force);
 
-      return getTasks(response);
+      AsyncTask<?, ?>[] tasks = getTasks(response);
+      return Arrays.copyOf(tasks, tasks.length, VirtualMachineTask[].class);
    }
 
    /**

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachine.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachine.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachine.java
index eac026e..a0df109 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachine.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachine.java
@@ -28,7 +28,8 @@ 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.task.VirtualMachineTask;
+import org.jclouds.abiquo.domain.task.VirtualMachineTemplateTask;
 import org.jclouds.abiquo.domain.util.LinkUtils;
 import org.jclouds.abiquo.features.services.MonitoringService;
 import org.jclouds.abiquo.monitor.VirtualMachineMonitor;
@@ -45,6 +46,7 @@ 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.VirtualMachineInstanceDto;
 import com.abiquo.server.core.cloud.VirtualMachineState;
 import com.abiquo.server.core.cloud.VirtualMachineStateDto;
 import com.abiquo.server.core.cloud.VirtualMachineTaskDto;
@@ -138,9 +140,9 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
     * @return The task reference or <code>null</code> if the operation completed
     *         synchronously.
     */
-   public AsyncTask update() {
+   public VirtualMachineTask update() {
       AcceptedRequestDto<String> taskRef = context.getApi().getCloudApi().updateVirtualMachine(target);
-      return taskRef == null ? null : getTask(taskRef);
+      return taskRef == null ? null : getTask(taskRef).asVirtualMachineTask();
    }
 
    /**
@@ -162,10 +164,10 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
     * @return The task reference or <code>null</code> if the operation completed
     *         synchronously.
     */
-   public AsyncTask update(final boolean force) {
+   public VirtualMachineTask update(final boolean force) {
       AcceptedRequestDto<String> taskRef = context.getApi().getCloudApi()
             .updateVirtualMachine(target, VirtualMachineOptions.builder().force(force).build());
-      return taskRef == null ? null : getTask(taskRef);
+      return taskRef == null ? null : getTask(taskRef).asVirtualMachineTask();
    }
 
    /**
@@ -187,13 +189,13 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
     * @return The task reference or <code>null</code> if the operation completed
     *         synchronously.
     */
-   public AsyncTask changeState(final VirtualMachineState state) {
+   public VirtualMachineTask changeState(final VirtualMachineState state) {
       VirtualMachineStateDto dto = new VirtualMachineStateDto();
       dto.setState(state);
 
       AcceptedRequestDto<String> taskRef = context.getApi().getCloudApi().changeVirtualMachineState(target, dto);
 
-      return getTask(taskRef);
+      return getTask(taskRef).asVirtualMachineTask();
    }
 
    /**
@@ -213,6 +215,26 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
       return state;
    }
 
+   /**
+    * Take a snapshot of the given virtual machine.
+    * <p>
+    * This will create a new {@link VirtualMachineTemplate} in the appliance
+    * library based on the given virtual machine.
+    * 
+    * @param snapshotName
+    *           The name of the snapshot.
+    * @return The task reference to the snapshot process.
+    */
+   public VirtualMachineTemplateTask snapshot(final String snapshotName) {
+      VirtualMachineInstanceDto snapshotConfig = new VirtualMachineInstanceDto();
+      snapshotConfig.setInstanceName(snapshotName);
+
+      AcceptedRequestDto<String> response = context.getApi().getCloudApi()
+            .snapshotVirtualMachine(target, snapshotConfig);
+
+      return getTask(response).asVirtualMachineTemplateTask();
+   }
+
    // Parent access
 
    /**
@@ -298,30 +320,30 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
 
    // Actions
 
-   public AsyncTask deploy() {
+   public VirtualMachineTask deploy() {
       return deploy(false);
    }
 
-   public AsyncTask deploy(final boolean forceEnterpriseSoftLimits) {
+   public VirtualMachineTask deploy(final boolean forceEnterpriseSoftLimits) {
       VirtualMachineTaskDto force = new VirtualMachineTaskDto();
       force.setForceEnterpriseSoftLimits(forceEnterpriseSoftLimits);
 
       AcceptedRequestDto<String> response = context.getApi().getCloudApi().deployVirtualMachine(unwrap(), force);
 
-      return getTask(response);
+      return getTask(response).asVirtualMachineTask();
    }
 
-   public AsyncTask undeploy() {
+   public VirtualMachineTask undeploy() {
       return undeploy(false);
    }
 
-   public AsyncTask undeploy(final boolean forceUndeploy) {
+   public VirtualMachineTask undeploy(final boolean forceUndeploy) {
       VirtualMachineTaskDto force = new VirtualMachineTaskDto();
       force.setForceUndeploy(forceUndeploy);
 
       AcceptedRequestDto<String> response = context.getApi().getCloudApi().undeployVirtualMachine(unwrap(), force);
 
-      return getTask(response);
+      return getTask(response).asVirtualMachineTask();
    }
 
    /**
@@ -342,13 +364,13 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
     * @return The task reference or <code>null</code> if the operation completed
     *         synchronously.
     */
-   public AsyncTask reboot() {
+   public VirtualMachineTask reboot() {
       AcceptedRequestDto<String> response = context.getApi().getCloudApi().rebootVirtualMachine(unwrap());
 
-      return getTask(response);
+      return getTask(response).asVirtualMachineTask();
    }
 
-   public AsyncTask attachHardDisks(final HardDisk... hardDisks) {
+   public VirtualMachineTask attachHardDisks(final HardDisk... hardDisks) {
       List<HardDisk> expected = Lists.newArrayList(listAttachedHardDisks());
       expected.addAll(Arrays.asList(hardDisks));
 
@@ -356,12 +378,12 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
       return setHardDisks(expected.toArray(disks));
    }
 
-   public AsyncTask detachAllHardDisks() {
+   public VirtualMachineTask detachAllHardDisks() {
       AcceptedRequestDto<String> taskRef = context.getApi().getCloudApi().detachAllHardDisks(target);
-      return taskRef == null ? null : getTask(taskRef);
+      return taskRef == null ? null : getTask(taskRef).asVirtualMachineTask();
    }
 
-   public AsyncTask detachHardDisks(final HardDisk... hardDisks) {
+   public VirtualMachineTask detachHardDisks(final HardDisk... hardDisks) {
       List<HardDisk> expected = Lists.newArrayList(listAttachedHardDisks());
       Iterables.removeIf(expected, hardDiskIdIn(hardDisks));
 
@@ -369,13 +391,13 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
       return setHardDisks(expected.toArray(disks));
    }
 
-   public AsyncTask setHardDisks(final HardDisk... hardDisks) {
+   public VirtualMachineTask setHardDisks(final HardDisk... hardDisks) {
       AcceptedRequestDto<String> taskRef = context.getApi().getCloudApi()
             .replaceHardDisks(target, toHardDiskDto(hardDisks));
-      return taskRef == null ? null : getTask(taskRef);
+      return taskRef == null ? null : getTask(taskRef).asVirtualMachineTask();
    }
 
-   public AsyncTask attachVolumes(final Volume... volumes) {
+   public VirtualMachineTask attachVolumes(final Volume... volumes) {
       List<Volume> expected = Lists.newArrayList(listAttachedVolumes());
       expected.addAll(Arrays.asList(volumes));
 
@@ -383,12 +405,12 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
       return setVolumes(true, expected.toArray(vols));
    }
 
-   public AsyncTask detachAllVolumes() {
+   public VirtualMachineTask detachAllVolumes() {
       AcceptedRequestDto<String> taskRef = context.getApi().getCloudApi().detachAllVolumes(target);
-      return taskRef == null ? null : getTask(taskRef);
+      return taskRef == null ? null : getTask(taskRef).asVirtualMachineTask();
    }
 
-   public AsyncTask detachVolumes(final Volume... volumes) {
+   public VirtualMachineTask detachVolumes(final Volume... volumes) {
       List<Volume> expected = Lists.newArrayList(listAttachedVolumes());
       Iterables.removeIf(expected, volumeIdIn(volumes));
 
@@ -396,26 +418,26 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
       return setVolumes(true, expected.toArray(vols));
    }
 
-   public AsyncTask setVolumes(final Boolean forceSoftLimits, final Volume... volumes) {
+   public VirtualMachineTask 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);
+      return taskRef == null ? null : getTask(taskRef).asVirtualMachineTask();
    }
 
-   public AsyncTask setVolumes(final Volume... volumes) {
+   public VirtualMachineTask setVolumes(final Volume... volumes) {
       return setVolumes(true, volumes);
    }
 
-   public AsyncTask setNics(final List<? extends Ip<?, ?>> ips) {
+   public VirtualMachineTask 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<? extends Ip<?, ?>> ips, final List<UnmanagedNetwork> unmanagedNetworks) {
+   public VirtualMachineTask setNics(final List<Ip<?, ?>> ips, final List<UnmanagedNetwork> unmanagedNetworks) {
       // By default the network of the first ip will be used as a gateway
       Network<?> gateway = null;
       if (ips != null && !ips.isEmpty()) {
@@ -427,11 +449,11 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
       return setNics(gateway, ips, unmanagedNetworks);
    }
 
-   public AsyncTask setNics(final Network<?> gatewayNetwork, final List<? extends Ip<?, ?>> ips) {
+   public VirtualMachineTask setNics(final Network<?> gatewayNetwork, final List<Ip<?, ?>> ips) {
       return setNics(gatewayNetwork, ips, null);
    }
 
-   public AsyncTask setNics(final Network<?> gatewayNetwork, final List<? extends Ip<?, ?>> ips,
+   public VirtualMachineTask setNics(final Network<?> gatewayNetwork, final List<Ip<?, ?>> ips,
          final List<UnmanagedNetwork> unmanagedNetworks) {
       // Remove the gateway configuration and the current nics
       Iterables.removeIf(target.getLinks(),
@@ -461,7 +483,7 @@ public class VirtualMachine extends DomainWithTasksWrapper<VirtualMachineWithNod
          }
       }
 
-      AsyncTask task = update(true);
+      VirtualMachineTask task = update(true);
       if (gatewayNetwork == null) {
          return task;
       }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplate.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplate.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplate.java
index 3a0e809..b3822d4 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplate.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/VirtualMachineTemplate.java
@@ -30,7 +30,8 @@ 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.domain.task.ConversionTask;
+import org.jclouds.abiquo.domain.task.VirtualMachineTemplateTask;
 import org.jclouds.abiquo.reference.rest.ParentLinkName;
 import org.jclouds.http.HttpResponse;
 import org.jclouds.http.functions.ParseXMLWithJAXB;
@@ -79,23 +80,15 @@ public class VirtualMachineTemplate extends DomainWrapper<VirtualMachineTemplate
       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) {
+   public VirtualMachineTemplateTask makePersistent(final VirtualDatacenter vdc, final Volume volume,
+         final String persistentTemplateName) {
       RESTLink storageLink = volume.unwrap().getEditLink();
       storageLink.setRel("volume");
       return makePersistent(vdc, storageLink, persistentTemplateName, null);
    }
 
-   public AsyncTask makePersistent(final VirtualDatacenter vdc, final Tier tier, final String persistentTemplateName,
-         final String persistentVolumeName) {
+   public VirtualMachineTemplateTask makePersistent(final VirtualDatacenter vdc, final Tier tier,
+         final String persistentTemplateName, final String persistentVolumeName) {
       // infrastructure
       RESTLink storageLink = tier.unwrap().getEditLink();
       if (storageLink == null) {
@@ -106,7 +99,7 @@ public class VirtualMachineTemplate extends DomainWrapper<VirtualMachineTemplate
       return makePersistent(vdc, storageLink, persistentTemplateName, persistentVolumeName);
    }
 
-   private AsyncTask makePersistent(final VirtualDatacenter vdc, final RESTLink storageLink,
+   private VirtualMachineTemplateTask makePersistent(final VirtualDatacenter vdc, final RESTLink storageLink,
          final String persistentTemplateName, final String persistentVolumeName) {
       VirtualMachineTemplatePersistentDto persistentData = new VirtualMachineTemplatePersistentDto();
       persistentData.setPersistentTemplateName(persistentTemplateName);
@@ -138,7 +131,7 @@ public class VirtualMachineTemplate extends DomainWrapper<VirtualMachineTemplate
       AcceptedRequestDto<String> response = context.getApi().getVirtualMachineTemplateApi()
             .createPersistentVirtualMachineTemplate(idEnt, idDcRepo, persistentData);
 
-      return getTask(response);
+      return getTask(response).asVirtualMachineTemplateTask();
    }
 
    // Children access
@@ -251,14 +244,14 @@ public class VirtualMachineTemplate extends DomainWrapper<VirtualMachineTemplate
     *           , desired target format for the request template
     * @return The task reference to track its progress
     */
-   public AsyncTask requestConversion(final DiskFormatType diskFormat) {
+   public ConversionTask 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);
+      return taskRef == null ? null : getTask(taskRef).asConversionTask();
    }
 
    // Delegate methods

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Volume.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Volume.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Volume.java
index 49de0dc..5cfbd17 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Volume.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/cloud/Volume.java
@@ -21,7 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 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.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.reference.ValidationErrors;
 
 import org.jclouds.abiquo.reference.rest.ParentLinkName;
@@ -70,9 +70,9 @@ public class Volume extends DomainWrapper<VolumeManagementDto> {
       target = context.getApi().getCloudApi().createVolume(virtualDatacenter.unwrap(), target);
    }
 
-   public AsyncTask update() {
+   public VirtualMachineTask update() {
       AcceptedRequestDto<String> taskRef = context.getApi().getCloudApi().updateVolume(target);
-      return taskRef == null ? null : getTask(taskRef);
+      return taskRef == null ? null : getTask(taskRef).asVirtualMachineTask();
    }
 
    // Parent access
@@ -90,9 +90,6 @@ public class Volume extends DomainWrapper<VolumeManagementDto> {
       return virtualDatacenter;
    }
 
-   /**
-    * TODO javadoc link
-    */
    public Tier getTier() {
       Integer tierId = target.getIdFromLink(ParentLinkName.TIER);
       TierDto dto = context.getApi().getCloudApi().getStorageTier(virtualDatacenter.unwrap(), tierId);

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Privilege.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Privilege.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Privilege.java
index 5e0e2ac..29e583b 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Privilege.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/config/Privilege.java
@@ -18,7 +18,6 @@ package org.jclouds.abiquo.domain.config;
 
 import org.jclouds.abiquo.AbiquoApi;
 import org.jclouds.abiquo.domain.DomainWrapper;
-
 import org.jclouds.rest.ApiContext;
 
 import com.abiquo.server.core.enterprise.PrivilegeDto;

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncTask.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncTask.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncTask.java
index 3fb4e6e..fca2827 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncTask.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/task/AsyncTask.java
@@ -23,24 +23,44 @@ import java.util.List;
 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.http.HttpResponse;
+import org.jclouds.http.functions.ParseXMLWithJAXB;
 import org.jclouds.rest.ApiContext;
 
 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.enums.TaskState;
 import com.abiquo.server.core.task.enums.TaskType;
+import com.google.inject.TypeLiteral;
 
 /**
  * Adds generic high level functionality to {TaskDto}.
  * 
+ * @author Ignasi Barrera
  * @author Francesc Montserrat
+ * @param <T>
+ *           The type of the result generated by the task.
+ * @param <D>
+ *           The type of the dto generated by the task.
  */
-public class AsyncTask extends DomainWrapper<TaskDto> {
+public abstract class AsyncTask<T extends DomainWrapper<D>, D extends SingleResourceTransportDto> extends
+      DomainWrapper<TaskDto> {
+   /** The type of the result generated by the task. */
+   private Class<T> resultDomainClass;
+
+   /** The type of the dto generated by the task. */
+   private Class<D> resultDtoClass;
+
    /**
     * Constructor to be used only by the builder.
     */
-   protected AsyncTask(final ApiContext<AbiquoApi> context, final TaskDto target) {
+   protected AsyncTask(final ApiContext<AbiquoApi> context, final TaskDto target, final Class<T> resultDomainClass,
+         final Class<D> resultDtoClass) {
       super(context, target);
+      this.resultDomainClass = resultDomainClass;
+      this.resultDtoClass = resultDtoClass;
    }
 
    // Domain operations
@@ -55,6 +75,19 @@ public class AsyncTask extends DomainWrapper<TaskDto> {
       target = context.getApi().getTaskApi().getTask(self);
    }
 
+   public T getResult() {
+      RESTLink link = target.searchLink(ParentLinkName.TASK_RESULT);
+      if (link == null) {
+         // The task may still be in progress or has failed
+         return null;
+      }
+
+      HttpResponse response = context.getApi().get(link);
+      ParseXMLWithJAXB<D> parser = new ParseXMLWithJAXB<D>(context.utils().xml(), TypeLiteral.get(resultDtoClass));
+
+      return wrap(context, resultDomainClass, parser.apply(response));
+   }
+
    // Children access
 
    /**
@@ -64,6 +97,20 @@ public class AsyncTask extends DomainWrapper<TaskDto> {
       return wrap(context, AsyncJob.class, target.getJobs().getCollection());
    }
 
+   // Conversion helpers
+
+   public ConversionTask asConversionTask() {
+      return ConversionTask.class.cast(this);
+   }
+
+   public VirtualMachineTask asVirtualMachineTask() {
+      return VirtualMachineTask.class.cast(this);
+   }
+
+   public VirtualMachineTemplateTask asVirtualMachineTemplateTask() {
+      return VirtualMachineTemplateTask.class.cast(this);
+   }
+
    // Delegate methods
 
    public String getOwnerId() {

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/task/ConversionTask.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/task/ConversionTask.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/task/ConversionTask.java
new file mode 100644
index 0000000..19c94c3
--- /dev/null
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/task/ConversionTask.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.task;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.cloud.Conversion;
+import org.jclouds.rest.ApiContext;
+
+import com.abiquo.server.core.appslibrary.ConversionDto;
+import com.abiquo.server.core.task.TaskDto;
+
+/**
+ * Task that produces a {@link Conversion}.
+ * 
+ * @author Ignasi Barrera
+ */
+public class ConversionTask extends AsyncTask<Conversion, ConversionDto> {
+   protected ConversionTask(final ApiContext<AbiquoApi> context, final TaskDto target) {
+      super(context, target, Conversion.class, ConversionDto.class);
+   }
+
+   @Override
+   public String toString() {
+      return "Conversion" + super.toString();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/task/VirtualMachineTask.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/task/VirtualMachineTask.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/task/VirtualMachineTask.java
new file mode 100644
index 0000000..ff07e5f
--- /dev/null
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/task/VirtualMachineTask.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.task;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.cloud.VirtualMachine;
+import org.jclouds.rest.ApiContext;
+
+import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
+import com.abiquo.server.core.task.TaskDto;
+
+/**
+ * Task that produces a {@link VirtualMachine}.
+ * 
+ * @author Ignasi Barrera
+ */
+public class VirtualMachineTask extends AsyncTask<VirtualMachine, VirtualMachineWithNodeExtendedDto> {
+   protected VirtualMachineTask(final ApiContext<AbiquoApi> context, final TaskDto target) {
+      super(context, target, VirtualMachine.class, VirtualMachineWithNodeExtendedDto.class);
+   }
+
+   @Override
+   public String toString() {
+      return "VirtualMachine" + super.toString();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/domain/task/VirtualMachineTemplateTask.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/domain/task/VirtualMachineTemplateTask.java b/abiquo/src/main/java/org/jclouds/abiquo/domain/task/VirtualMachineTemplateTask.java
new file mode 100644
index 0000000..15ec1be
--- /dev/null
+++ b/abiquo/src/main/java/org/jclouds/abiquo/domain/task/VirtualMachineTemplateTask.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.task;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.abiquo.domain.cloud.VirtualMachineTemplate;
+import org.jclouds.rest.ApiContext;
+
+import com.abiquo.server.core.appslibrary.VirtualMachineTemplateDto;
+import com.abiquo.server.core.task.TaskDto;
+
+/**
+ * Task that produces a {@link VirtualMachineTemplate}.
+ * 
+ * @author Ignasi Barrera
+ */
+public class VirtualMachineTemplateTask extends AsyncTask<VirtualMachineTemplate, VirtualMachineTemplateDto> {
+   protected VirtualMachineTemplateTask(final ApiContext<AbiquoApi> context, final TaskDto target) {
+      super(context, target, VirtualMachineTemplate.class, VirtualMachineTemplateDto.class);
+   }
+
+   @Override
+   public String toString() {
+      return "VirtualMachineTemplate" + super.toString();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/features/CloudApi.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/features/CloudApi.java b/abiquo/src/main/java/org/jclouds/abiquo/features/CloudApi.java
index 65d02f9..c888f66 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/features/CloudApi.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/features/CloudApi.java
@@ -72,6 +72,7 @@ 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.VirtualMachineInstanceDto;
 import com.abiquo.server.core.cloud.VirtualMachineStateDto;
 import com.abiquo.server.core.cloud.VirtualMachineTaskDto;
 import com.abiquo.server.core.cloud.VirtualMachineWithNodeExtendedDto;
@@ -841,6 +842,27 @@ public interface CloudApi extends Closeable {
    AcceptedRequestDto<String> rebootVirtualMachine(
          @EndpointLink("reset") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine);
 
+   /**
+    * Take a snapshot of the given virtual machine.
+    * <p>
+    * This will create a new virtual machine template in the appliance library
+    * based on the given virtual machine.
+    * 
+    * @param virtualMachine
+    *           The virtual machine to snapshot.
+    * @param snapshotConfig
+    *           The configuration of the snapshot.
+    * @return The task reference to the snapshot process.
+    */
+   @Named("vm:snapshot")
+   @POST
+   @Consumes(AcceptedRequestDto.BASE_MEDIA_TYPE)
+   @Produces(VirtualMachineInstanceDto.BASE_MEDIA_TYPE)
+   @JAXBResponseParser
+   AcceptedRequestDto<String> snapshotVirtualMachine(
+         @EndpointLink("instance") @BinderParam(BindToPath.class) VirtualMachineDto virtualMachine,
+         @BinderParam(BindToXMLPayload.class) VirtualMachineInstanceDto snapshotConfig);
+
    /******************* Virtual Machine Template ***********************/
 
    /**

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/monitor/AsyncTaskMonitor.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/monitor/AsyncTaskMonitor.java b/abiquo/src/main/java/org/jclouds/abiquo/monitor/AsyncTaskMonitor.java
index 1e6b24c..dfcc7a5 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/monitor/AsyncTaskMonitor.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/monitor/AsyncTaskMonitor.java
@@ -38,7 +38,7 @@ public interface AsyncTaskMonitor extends MonitoringService {
     * @param tasks
     *           The {@link AsyncTask}s to monitor.
     */
-   void awaitCompletion(final AsyncTask... tasks);
+   void awaitCompletion(final AsyncTask<?, ?>... tasks);
 
    /**
     * Monitor the given {@link AsyncTask}s and populate an event when they
@@ -47,7 +47,7 @@ public interface AsyncTaskMonitor extends MonitoringService {
     * @param tasks
     *           The {@link AsyncTask}s to monitor.
     */
-   public void monitor(final AsyncTask... tasks);
+   public void monitor(final AsyncTask<?, ?>... tasks);
 
    /**
     * Monitor the given {@link AsyncTask}s and block until they finish.
@@ -59,7 +59,7 @@ public interface AsyncTaskMonitor extends MonitoringService {
     * @param tasks
     *           The {@link AsyncTask}s to monitor.
     */
-   void awaitCompletion(final Long maxWait, final TimeUnit timeUnit, final AsyncTask... tasks);
+   void awaitCompletion(final Long maxWait, final TimeUnit timeUnit, final AsyncTask<?, ?>... tasks);
 
    /**
     * Monitor the given {@link AsyncTask}s and populate an event when they
@@ -72,5 +72,5 @@ public interface AsyncTaskMonitor extends MonitoringService {
     * @param tasks
     *           The {@link AsyncTask}s to monitor.
     */
-   public void monitor(final Long maxWait, final TimeUnit timeUnit, final AsyncTask... tasks);
+   public void monitor(final Long maxWait, final TimeUnit timeUnit, final AsyncTask<?, ?>... tasks);
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitor.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitor.java b/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitor.java
index 4fb462b..496b319 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitor.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitor.java
@@ -33,12 +33,12 @@ import com.google.common.base.Function;
  * @author Ignasi Barrera
  */
 @Singleton
-public class AsyncTaskStatusMonitor implements Function<AsyncTask, MonitorStatus> {
+public class AsyncTaskStatusMonitor implements Function<AsyncTask<?, ?>, MonitorStatus> {
    @Resource
    protected Logger logger = Logger.NULL;
 
    @Override
-   public MonitorStatus apply(final AsyncTask asyncTask) {
+   public MonitorStatus apply(final AsyncTask<?, ?> asyncTask) {
       checkNotNull(asyncTask, "asyncTask");
 
       try {

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitor.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitor.java b/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitor.java
index ad8b4cc..db244b3 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitor.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/monitor/internal/BaseAsyncTaskMonitor.java
@@ -58,22 +58,22 @@ public class BaseAsyncTaskMonitor extends BaseMonitoringService implements Async
    }
 
    @Override
-   public void awaitCompletion(final AsyncTask... tasks) {
+   public void awaitCompletion(final AsyncTask<?, ?>... tasks) {
       awaitCompletion(taskMonitor, tasks);
    }
 
    @Override
-   public void monitor(final AsyncTask... tasks) {
+   public void monitor(final AsyncTask<?, ?>... tasks) {
       monitor(taskMonitor, tasks);
    }
 
    @Override
-   public void awaitCompletion(final Long maxWait, final TimeUnit timeUnit, final AsyncTask... tasks) {
+   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) {
+   public void monitor(final Long maxWait, final TimeUnit timeUnit, final AsyncTask<?, ?>... tasks) {
       monitor(maxWait, timeUnit, taskMonitor, tasks);
    }
 

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/main/java/org/jclouds/abiquo/reference/rest/ParentLinkName.java
----------------------------------------------------------------------
diff --git a/abiquo/src/main/java/org/jclouds/abiquo/reference/rest/ParentLinkName.java b/abiquo/src/main/java/org/jclouds/abiquo/reference/rest/ParentLinkName.java
index 996812b..5ede05e 100644
--- a/abiquo/src/main/java/org/jclouds/abiquo/reference/rest/ParentLinkName.java
+++ b/abiquo/src/main/java/org/jclouds/abiquo/reference/rest/ParentLinkName.java
@@ -57,4 +57,6 @@ public class ParentLinkName {
    public static final String NETWORK_CONFIGURATIONS = "configurations";
 
    public static final String NETWORK_GATEWAY = "network_configuration";
+
+   public final static String TASK_RESULT = "result";
 }

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualApplianceLiveTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualApplianceLiveTest.java b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualApplianceLiveTest.java
index 4be19aa..8ba0214 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualApplianceLiveTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualApplianceLiveTest.java
@@ -25,7 +25,7 @@ import static org.testng.Assert.assertNull;
 
 import java.util.concurrent.TimeUnit;
 
-import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.features.services.MonitoringService;
 import org.jclouds.abiquo.internal.BaseAbiquoLiveApiTest;
 import org.testng.annotations.BeforeClass;
@@ -90,7 +90,7 @@ public class VirtualApplianceLiveTest extends BaseAbiquoLiveApiTest {
       vm.save();
       assertNotNull(vm.getId());
 
-      AsyncTask[] tasks = vapp.deploy();
+      VirtualMachineTask[] tasks = vapp.deploy();
       assertEquals(tasks.length, 1); // One task for each VM in the VAPP
 
       monitoringService.getVirtualApplianceMonitor().awaitCompletionDeploy(MAX_WAIT, TimeUnit.MINUTES, vapp);
@@ -100,7 +100,7 @@ public class VirtualApplianceLiveTest extends BaseAbiquoLiveApiTest {
 
    @Test(dependsOnMethods = "testDeployVirtualAppliance")
    public void testUndeployVirtualAppliance() {
-      AsyncTask[] tasks = vapp.undeploy();
+      VirtualMachineTask[] tasks = vapp.undeploy();
       assertEquals(tasks.length, 1); // One task for each VM in the VAPP
 
       monitoringService.getVirtualApplianceMonitor().awaitCompletionUndeploy(MAX_WAIT, TimeUnit.MINUTES, vapp);

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveApiTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveApiTest.java b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveApiTest.java
index 6ff8a8f..7623675 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveApiTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveApiTest.java
@@ -30,6 +30,7 @@ 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.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
 import org.testng.annotations.Test;
 
@@ -58,7 +59,7 @@ public class VirtualMachineLiveApiTest extends BaseAbiquoApiLiveApiTest {
    }
 
    public void testGetTasks() {
-      List<AsyncTask> tasks = env.virtualMachine.listTasks();
+      List<AsyncTask<?, ?>> tasks = env.virtualMachine.listTasks();
       assertNotNull(tasks);
    }
 
@@ -100,7 +101,7 @@ public class VirtualMachineLiveApiTest extends BaseAbiquoApiLiveApiTest {
       try {
          VirtualMachine vm = env.virtualAppliance.getVirtualMachine(env.virtualMachine.getId());
          vm.setCpu(7);
-         AsyncTask task = vm.update(true);
+         VirtualMachineTask task = vm.update(true);
 
          assertNull(task);
          assertEquals(vm.getCpu().intValue(), 7);

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveTest.java b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveTest.java
index 1d2aedd..3a2eb1a 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineLiveTest.java
@@ -32,7 +32,7 @@ import javax.ws.rs.core.Response.Status;
 import org.jclouds.abiquo.domain.enterprise.Enterprise;
 import org.jclouds.abiquo.domain.exception.AbiquoException;
 import org.jclouds.abiquo.domain.network.Ip;
-import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.features.services.MonitoringService;
 import org.jclouds.abiquo.internal.BaseAbiquoLiveApiTest;
 import org.testng.annotations.AfterClass;
@@ -96,7 +96,7 @@ public class VirtualMachineLiveTest extends BaseAbiquoLiveApiTest {
    @Test(dependsOnMethods = "testCreateVirtualMachine")
    public void testUpdateVirtualMachineWhenNotDeployed() {
       vm.setNameLabel(PREFIX + "VM Kane Updated");
-      AsyncTask task = vm.update();
+      VirtualMachineTask task = vm.update();
       assertNull(task);
 
       find(vapp.listVirtualMachines(), new Predicate<VirtualMachine>() {
@@ -109,7 +109,7 @@ public class VirtualMachineLiveTest extends BaseAbiquoLiveApiTest {
 
    @Test(dependsOnMethods = "testUpdateVirtualMachineWhenNotDeployed")
    public void testDeployVirtualMachine() {
-      AsyncTask task = vm.deploy(true);
+      VirtualMachineTask task = vm.deploy(true);
       assertNotNull(task);
 
       monitoringService.getVirtualMachineMonitor().awaitCompletionDeploy(MAX_WAIT, TimeUnit.MINUTES, vm);
@@ -118,7 +118,7 @@ public class VirtualMachineLiveTest extends BaseAbiquoLiveApiTest {
 
    @Test(dependsOnMethods = "testDeployVirtualMachine")
    public void testChangeVirtualMachineState() {
-      AsyncTask task = vm.changeState(VirtualMachineState.OFF);
+      VirtualMachineTask task = vm.changeState(VirtualMachineState.OFF);
       assertNotNull(task);
 
       monitoringService.getVirtualMachineMonitor().awaitState(MAX_WAIT, TimeUnit.MINUTES, VirtualMachineState.OFF, vm);
@@ -129,7 +129,7 @@ public class VirtualMachineLiveTest extends BaseAbiquoLiveApiTest {
    public void testReconfigure() {
       final Ip<?, ?> ip = getLast(vdc.getDefaultNetwork().listUnusedIps());
 
-      AsyncTask task = vm.setNics(Lists.<Ip<?, ?>> newArrayList(ip));
+      VirtualMachineTask task = vm.setNics(Lists.<Ip<?, ?>> newArrayList(ip));
       assertNotNull(task);
 
       monitoringService.getVirtualMachineMonitor().awaitState(MAX_WAIT, TimeUnit.MINUTES, VirtualMachineState.OFF, vm);
@@ -144,7 +144,7 @@ public class VirtualMachineLiveTest extends BaseAbiquoLiveApiTest {
 
    @Test(dependsOnMethods = "testReconfigure")
    public void testUndeployVirtualMachine() {
-      AsyncTask task = vm.undeploy();
+      VirtualMachineTask task = vm.undeploy();
       assertNotNull(task);
 
       monitoringService.getVirtualMachineMonitor().awaitCompletionUndeploy(MAX_WAIT, TimeUnit.MINUTES, vm);
@@ -161,7 +161,7 @@ public class VirtualMachineLiveTest extends BaseAbiquoLiveApiTest {
          vm.setCpu(ent.getCpuCountHardLimit() + 1);
       }
 
-      AsyncTask task = vm.update();
+      VirtualMachineTask task = vm.update();
       assertNull(task);
 
       try {

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineNetworkingLiveApiTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineNetworkingLiveApiTest.java b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineNetworkingLiveApiTest.java
index c1fc61b..ae0a31f 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineNetworkingLiveApiTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineNetworkingLiveApiTest.java
@@ -35,7 +35,7 @@ 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.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -84,7 +84,7 @@ public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTes
 
    @AfterClass
    public void restorePrivateIp() {
-      AsyncTask task = env.virtualMachine.setNics(Lists.<Ip<?, ?>> newArrayList(privateIp));
+      VirtualMachineTask task = env.virtualMachine.setNics(Lists.<Ip<?, ?>> newArrayList(privateIp));
       assertNull(task);
 
       List<Ip<?, ?>> nics = env.virtualMachine.listAttachedNics();
@@ -105,7 +105,7 @@ public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTes
    // 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));
+      VirtualMachineTask task = env.virtualMachine.setNics(Lists.<Ip<?, ?>> newArrayList(publicIpInfrastructure));
       assertNull(task);
 
       List<Ip<?, ?>> nics = env.virtualMachine.listAttachedNics();
@@ -114,7 +114,7 @@ public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTes
    }
 
    public void testAttachPublicIp() {
-      AsyncTask task = env.virtualMachine.setNics(Lists.<Ip<?, ?>> newArrayList(publicIpCloud));
+      VirtualMachineTask task = env.virtualMachine.setNics(Lists.<Ip<?, ?>> newArrayList(publicIpCloud));
       assertNull(task);
 
       List<Ip<?, ?>> nics = env.virtualMachine.listAttachedNics();
@@ -127,7 +127,7 @@ public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTes
       List<Ip<?, ?>> nics = Lists.newArrayList(env.virtualMachine.listAttachedNics());
       nics.add(privateIp);
 
-      AsyncTask task = env.virtualMachine.setNics(nics);
+      VirtualMachineTask task = env.virtualMachine.setNics(nics);
       assertNull(task);
 
       nics = env.virtualMachine.listAttachedNics();
@@ -141,7 +141,7 @@ public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTes
       List<Ip<?, ?>> nics = Lists.newArrayList(env.virtualMachine.listAttachedNics());
       nics.add(externalIp);
 
-      AsyncTask task = env.virtualMachine.setNics(nics);
+      VirtualMachineTask task = env.virtualMachine.setNics(nics);
       assertNull(task);
 
       nics = env.virtualMachine.listAttachedNics();
@@ -155,7 +155,7 @@ public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTes
    public void testAddUnmanagedNics() {
       List<Ip<?, ?>> nics = env.virtualMachine.listAttachedNics();
 
-      AsyncTask task = env.virtualMachine.setNics(nics,
+      VirtualMachineTask task = env.virtualMachine.setNics(nics,
             Lists.<UnmanagedNetwork> newArrayList(env.unmanagedNetwork, env.unmanagedNetwork));
       assertNull(task);
 
@@ -176,8 +176,8 @@ public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTes
    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)));
+      VirtualMachineTask 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();
@@ -193,7 +193,7 @@ public class VirtualMachineNetworkingLiveApiTest extends BaseAbiquoApiLiveApiTes
    public void testDetachNics() {
       List<Ip<?, ?>> nics = env.virtualMachine.listAttachedNics();
 
-      AsyncTask task = env.virtualMachine.setNics(Lists.<Ip<?, ?>> newArrayList(nics.get(1), nics.get(2)));
+      VirtualMachineTask task = env.virtualMachine.setNics(Lists.<Ip<?, ?>> newArrayList(nics.get(1), nics.get(2)));
       assertNull(task);
 
       nics = env.virtualMachine.listAttachedNics();

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineStorageLiveApiTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineStorageLiveApiTest.java b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineStorageLiveApiTest.java
index 82a2708..ea060cb 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineStorageLiveApiTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VirtualMachineStorageLiveApiTest.java
@@ -26,7 +26,7 @@ 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.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
 import org.testng.annotations.Test;
 
@@ -48,7 +48,7 @@ public class VirtualMachineStorageLiveApiTest extends BaseAbiquoApiLiveApiTest {
 
       // Since the virtual machine is not deployed, this should not generate a
       // task
-      AsyncTask task = env.virtualMachine.attachVolumes(volume);
+      VirtualMachineTask task = env.virtualMachine.attachVolumes(volume);
       assertNull(task);
 
       List<Volume> attached = env.virtualMachine.listAttachedVolumes();
@@ -67,7 +67,7 @@ public class VirtualMachineStorageLiveApiTest extends BaseAbiquoApiLiveApiTest {
    public void detachAllVolumes() {
       // Since the virtual machine is not deployed, this should not generate a
       // task
-      AsyncTask task = env.virtualMachine.attachVolumes(volume);
+      VirtualMachineTask task = env.virtualMachine.attachVolumes(volume);
       assertNull(task);
 
       env.virtualMachine.detachAllVolumes();
@@ -82,7 +82,7 @@ public class VirtualMachineStorageLiveApiTest extends BaseAbiquoApiLiveApiTest {
 
       // Since the virtual machine is not deployed, this should not generate a
       // task
-      AsyncTask task = env.virtualMachine.attachHardDisks(hardDisk);
+      VirtualMachineTask task = env.virtualMachine.attachHardDisks(hardDisk);
       assertNull(task);
 
       List<HardDisk> attached = env.virtualMachine.listAttachedHardDisks();
@@ -101,7 +101,7 @@ public class VirtualMachineStorageLiveApiTest extends BaseAbiquoApiLiveApiTest {
    public void detachAllHardDisks() {
       // Since the virtual machine is not deployed, this should not generate a
       // task
-      AsyncTask task = env.virtualMachine.attachHardDisks(hardDisk);
+      VirtualMachineTask task = env.virtualMachine.attachHardDisks(hardDisk);
       assertNull(task);
 
       env.virtualMachine.detachAllHardDisks();

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VolumeLiveApiTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VolumeLiveApiTest.java b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VolumeLiveApiTest.java
index a671989..02ec993 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VolumeLiveApiTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/domain/cloud/VolumeLiveApiTest.java
@@ -28,7 +28,7 @@ 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.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.internal.BaseAbiquoApiLiveApiTest;
 import org.testng.annotations.Test;
 
@@ -79,7 +79,7 @@ public class VolumeLiveApiTest extends BaseAbiquoApiLiveApiTest {
       Volume volume = find(env.virtualDatacenter.listVolumes(), volumeName(PREFIX + "Hawaian volume"));
 
       volume.setName("Hawaian volume updated");
-      AsyncTask task = volume.update();
+      VirtualMachineTask task = volume.update();
       assertNull(task);
 
       // Reload the volume to check

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiExpectTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiExpectTest.java b/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiExpectTest.java
new file mode 100644
index 0000000..57f7cf6
--- /dev/null
+++ b/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiExpectTest.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.features;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.net.URI;
+
+import org.jclouds.abiquo.AbiquoApi;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+import com.abiquo.model.rest.RESTLink;
+import com.abiquo.model.transport.AcceptedRequestDto;
+import com.abiquo.server.core.cloud.VirtualMachineDto;
+import com.abiquo.server.core.cloud.VirtualMachineInstanceDto;
+
+/**
+ * Expect tests for the {@link CloudApi} class.
+ * 
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "CloudApiExpectTest")
+public class CloudApiExpectTest extends BaseAbiquoApiExpectTest<CloudApi> {
+
+   public void testSnapshotVirtualMachineReturns2xx() {
+      CloudApi api = requestSendsResponse(
+            HttpRequest
+                  .builder()
+                  .method("POST")
+                  .endpoint(
+                        URI.create("http://localhost/api/admin/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/instance")) //
+                  .addHeader("Authorization", basicAuth) //
+                  .addHeader("Accept", normalize(AcceptedRequestDto.MEDIA_TYPE)) //
+                  .payload(
+                        payloadFromResourceWithContentType("/payloads/vm-snapshot.xml",
+                              normalize(VirtualMachineInstanceDto.MEDIA_TYPE))) //
+                  .build(), //
+            HttpResponse
+                  .builder()
+                  .statusCode(202)
+                  .payload(
+                        payloadFromResourceWithContentType("/payloads/vm-accepted-request.xml",
+                              normalize(VirtualMachineInstanceDto.MEDIA_TYPE))).build());
+
+      VirtualMachineDto vm = new VirtualMachineDto();
+      vm.addLink(new RESTLink("instance",
+            "http://localhost/api/admin/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/action/instance"));
+      VirtualMachineInstanceDto snapshotConfig = new VirtualMachineInstanceDto();
+      snapshotConfig.setInstanceName("foo");
+
+      AcceptedRequestDto<String> taskRef = api.snapshotVirtualMachine(vm, snapshotConfig);
+      assertNotNull(taskRef);
+   }
+
+   @Override
+   protected CloudApi clientFrom(AbiquoApi api) {
+      return api.getCloudApi();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiTest.java b/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiTest.java
index 8555f21..c2c73fb 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/features/CloudApiTest.java
@@ -1117,7 +1117,6 @@ public class CloudApiTest extends BaseAbiquoApiTest<CloudApi> {
 
    public void testGetHardDisk() throws SecurityException, NoSuchMethodException, IOException {
       Invokable<?, ?> method = method(CloudApi.class, "getHardDisk", VirtualDatacenterDto.class, Integer.class);
-      ;
       GeneratedHttpRequest request = processor.apply(Invocation.create(method,
             ImmutableList.<Object> of(CloudResources.virtualDatacenterPut(), 1)));
 

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/features/InfrastructureApiExpectTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/features/InfrastructureApiExpectTest.java b/abiquo/src/test/java/org/jclouds/abiquo/features/InfrastructureApiExpectTest.java
index c2e11e4..72b58ec 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/features/InfrastructureApiExpectTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/features/InfrastructureApiExpectTest.java
@@ -33,7 +33,7 @@ import com.abiquo.server.core.infrastructure.network.NetworkServiceTypeDto;
 import com.abiquo.server.core.infrastructure.network.NetworkServiceTypesDto;
 
 /**
- * xpect tests for the {@link InfrastructureApi} class.
+ * Expect tests for the {@link InfrastructureApi} class.
  * 
  * @author Ignasi Barrera
  */

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitorTest.java
----------------------------------------------------------------------
diff --git a/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitorTest.java b/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitorTest.java
index 8c8ba32..5c59d9a 100644
--- a/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitorTest.java
+++ b/abiquo/src/test/java/org/jclouds/abiquo/monitor/functions/AsyncTaskStatusMonitorTest.java
@@ -20,6 +20,7 @@ import static org.testng.Assert.assertEquals;
 
 import org.easymock.EasyMock;
 import org.jclouds.abiquo.domain.task.AsyncTask;
+import org.jclouds.abiquo.domain.task.VirtualMachineTask;
 import org.jclouds.abiquo.monitor.MonitorStatus;
 import org.jclouds.rest.ApiContext;
 import org.testng.annotations.Test;
@@ -38,7 +39,7 @@ public class AsyncTaskStatusMonitorTest {
 
    @Test(expectedExceptions = NullPointerException.class)
    public void testInvalidNullArgument() {
-      Function<AsyncTask, MonitorStatus> function = new AsyncTaskStatusMonitor();
+      Function<AsyncTask<?, ?>, MonitorStatus> function = new AsyncTaskStatusMonitor();
       function.apply(null);
    }
 
@@ -62,7 +63,7 @@ public class AsyncTaskStatusMonitorTest {
       checkStatesReturn(new MockAsyncTaskFailing(), new AsyncTaskStatusMonitor(), states, MonitorStatus.CONTINUE);
    }
 
-   private void checkStatesReturn(final MockAsyncTask task, final Function<AsyncTask, MonitorStatus> function,
+   private void checkStatesReturn(final MockAsyncTask task, final Function<AsyncTask<?, ?>, MonitorStatus> function,
          final TaskState[] states, final MonitorStatus expectedStatus) {
       for (TaskState state : states) {
          task.setState(state);
@@ -70,7 +71,7 @@ public class AsyncTaskStatusMonitorTest {
       }
    }
 
-   private static class MockAsyncTask extends AsyncTask {
+   private static class MockAsyncTask extends VirtualMachineTask {
       @SuppressWarnings("unchecked")
       public MockAsyncTask() {
          super(EasyMock.createMock(ApiContext.class), new TaskDto());

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/resources/payloads/vm-accepted-request.xml
----------------------------------------------------------------------
diff --git a/abiquo/src/test/resources/payloads/vm-accepted-request.xml b/abiquo/src/test/resources/payloads/vm-accepted-request.xml
new file mode 100644
index 0000000..2efc649
--- /dev/null
+++ b/abiquo/src/test/resources/payloads/vm-accepted-request.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<acceptedrequest>
+    <link rel="task" href="http://localhost/api/cloud/virtualdatacenters/1/virtualappliances/1/virtualmachines/1/tasks/169f1877-5f17-4f62-9563-974001295c54" />
+</acceptedrequest>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-jclouds-labs/blob/726b1f3e/abiquo/src/test/resources/payloads/vm-snapshot.xml
----------------------------------------------------------------------
diff --git a/abiquo/src/test/resources/payloads/vm-snapshot.xml b/abiquo/src/test/resources/payloads/vm-snapshot.xml
new file mode 100644
index 0000000..7e28a7b
--- /dev/null
+++ b/abiquo/src/test/resources/payloads/vm-snapshot.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<virtualmachineinstance>
+    <instanceName>foo</instanceName>
+</virtualmachineinstance>