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 2016/10/28 14:31:40 UTC

[2/2] jclouds-labs git commit: Track status of requests that return the Location header

Track status of requests that return the Location header


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

Branch: refs/heads/master
Commit: c4e36e72e01341e82250801e65860f07859e61ca
Parents: 436c001
Author: Ignasi Barrera <na...@apache.org>
Authored: Thu Oct 27 17:51:58 2016 +0200
Committer: Ignasi Barrera <na...@apache.org>
Committed: Fri Oct 28 16:30:54 2016 +0200

----------------------------------------------------------------------
 profitbricks-rest/pom.xml                       |   2 +-
 .../profitbricks/rest/ProfitBricksApi.java      |  32 ++++-
 .../binder/BaseProfitBricksRequestBinder.java   |   7 +-
 .../snapshot/UpdateSnapshotRequestBinder.java   |   1 +
 .../volume/CreateSnapshotRequestBinder.java     |   1 +
 .../volume/RestoreSnapshotRequestBinder.java    |   1 +
 .../ProfitBricksComputeServiceAdapter.java      | 120 +++++++++-------
 .../compute/concurrent/ProvisioningJob.java     |  15 +-
 ...ProfitBricksComputeServiceContextModule.java |   1 +
 .../compute/function/ProvisionableToImage.java  |  16 ++-
 .../ServerInDataCenterToNodeMetadata.java       |   2 +
 .../strategy/AssignDataCenterToTemplate.java    |  28 ++--
 .../rest/config/ProfitBricksHttpApiModule.java  |  50 ++++++-
 .../profitbricks/rest/domain/DataCenter.java    |   2 +-
 .../profitbricks/rest/domain/FirewallRule.java  |   2 +-
 .../jclouds/profitbricks/rest/domain/Image.java |   2 +-
 .../profitbricks/rest/domain/IpBlock.java       |   2 +-
 .../jclouds/profitbricks/rest/domain/Lan.java   |   2 +-
 .../jclouds/profitbricks/rest/domain/Nic.java   |   2 +-
 .../profitbricks/rest/domain/RequestStatus.java |  92 ++++++++++++
 .../profitbricks/rest/domain/Server.java        |   2 +-
 .../profitbricks/rest/domain/Snapshot.java      |   2 +-
 .../profitbricks/rest/domain/Trackable.java     |  41 ++++++
 .../profitbricks/rest/domain/Volume.java        |   2 +-
 .../rest/features/DataCenterApi.java            |  27 ++--
 .../profitbricks/rest/features/FirewallApi.java |  23 +--
 .../profitbricks/rest/features/ImageApi.java    |  16 ++-
 .../profitbricks/rest/features/IpBlockApi.java  |  20 ++-
 .../profitbricks/rest/features/LanApi.java      |  21 ++-
 .../profitbricks/rest/features/NicApi.java      |  21 ++-
 .../profitbricks/rest/features/ServerApi.java   |  36 +++--
 .../profitbricks/rest/features/SnapshotApi.java |  20 ++-
 .../profitbricks/rest/features/VolumeApi.java   |  24 ++--
 .../rest/functions/ParseRequestStatusURI.java   |  39 ++++++
 .../rest/functions/RequestStatusURIParser.java  |  50 +++++++
 .../rest/util/ApiPredicatesModule.java          | 140 -------------------
 .../jclouds/profitbricks/rest/util/ParseId.java |   1 +
 .../profitbricks/rest/util/Trackables.java      |  67 +++++++++
 .../server/AttachCdromRequestBinderTest.java    |   1 +
 .../server/AttachVolumeRequestBinderTest.java   |   1 +
 .../volume/CreateSnapshotRequestBinderTest.java |   1 +
 .../volume/UpdateVolumeRequestBinderTest.java   |   1 +
 .../concurrent/ProvisioningManagerTest.java     |   4 +-
 .../rest/features/DataCenterApiLiveTest.java    |   1 +
 .../rest/features/DataCenterApiMockTest.java    |  14 +-
 .../rest/features/FirewallApiLiveTest.java      |  12 +-
 .../rest/features/IpblockApiLiveTest.java       |   6 +-
 .../rest/features/LanApiLiveTest.java           |  29 ++--
 .../rest/features/NicApiLiveTest.java           |  12 +-
 .../rest/features/ServerApiLiveTest.java        |  28 ++--
 .../rest/features/SnapshotApiLiveTest.java      |  18 +--
 .../rest/features/VolumeApiLiveTest.java        |  13 +-
 .../internal/BaseProfitBricksApiMockTest.java   |  28 ++--
 .../rest/internal/BaseProfitBricksLiveTest.java |  55 +++++---
 .../profitbricks/rest/util/ParseIdTest.java     |   1 +
 55 files changed, 773 insertions(+), 384 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/pom.xml
----------------------------------------------------------------------
diff --git a/profitbricks-rest/pom.xml b/profitbricks-rest/pom.xml
index 0f1b41d..3cb63f0 100644
--- a/profitbricks-rest/pom.xml
+++ b/profitbricks-rest/pom.xml
@@ -32,7 +32,7 @@
     <packaging>bundle</packaging>
 
     <properties>
-        <test.profitbricks-rest.endpoint>https://api.profitbricks.com/1.3</test.profitbricks-rest.endpoint>
+        <test.profitbricks-rest.endpoint>https://api.profitbricks.com/rest/v2/</test.profitbricks-rest.endpoint>
         <test.profitbricks-rest.identity>FIXME</test.profitbricks-rest.identity>
         <test.profitbricks-rest.credential>FIXME</test.profitbricks-rest.credential>
         <test.profitbricks-rest.api-version>1.3</test.profitbricks-rest.api-version>

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApi.java
index 7c4b2b9..dc14b12 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApi.java
@@ -16,8 +16,14 @@
  */
 package org.apache.jclouds.profitbricks.rest;
 
-import com.google.common.annotations.Beta;
 import java.io.Closeable;
+import java.net.URI;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.ws.rs.GET;
+
+import org.apache.jclouds.profitbricks.rest.domain.RequestStatus;
 import org.apache.jclouds.profitbricks.rest.features.DataCenterApi;
 import org.apache.jclouds.profitbricks.rest.features.FirewallApi;
 import org.apache.jclouds.profitbricks.rest.features.ImageApi;
@@ -27,7 +33,18 @@ import org.apache.jclouds.profitbricks.rest.features.NicApi;
 import org.apache.jclouds.profitbricks.rest.features.ServerApi;
 import org.apache.jclouds.profitbricks.rest.features.SnapshotApi;
 import org.apache.jclouds.profitbricks.rest.features.VolumeApi;
+import org.jclouds.Fallbacks;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.EndpointParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+
+import com.google.common.annotations.Beta;
+import com.google.inject.TypeLiteral;
 
 @Beta
 public interface ProfitBricksApi extends Closeable {
@@ -58,5 +75,18 @@ public interface ProfitBricksApi extends Closeable {
 
    @Delegate
    IpBlockApi ipBlockApi();
+   
+   @Named("request:status")
+   @GET
+   @RequestFilters(BasicAuthentication.class)
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @ResponseParser(RequestStatusParser.class)
+   RequestStatus getRequestStatus(@EndpointParam URI requestStatusURI);
+   
+   static final class RequestStatusParser extends ParseJson<RequestStatus> {
+      @Inject RequestStatusParser(Json json) {
+         super(json, TypeLiteral.get(RequestStatus.class));
+      }
+   }
 
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/BaseProfitBricksRequestBinder.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/BaseProfitBricksRequestBinder.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/BaseProfitBricksRequestBinder.java
index d0f4a05..b5bf528 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/BaseProfitBricksRequestBinder.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/BaseProfitBricksRequestBinder.java
@@ -44,14 +44,12 @@ public abstract class BaseProfitBricksRequestBinder<T> implements MapBinder {
       this.endpointSupplier = endpointSupplier;
    }
 
+   @SuppressWarnings("unchecked")
    @Override
    public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
       checkNotNull(request, "request");
-
       Object obj = checkNotNull(postParams.get(paramName), "Param '%s' cannot be null.", paramName);
-      T payload = (T) obj;
-
-      return createRequest(request, createPayload(payload));
+      return createRequest(request, createPayload((T) obj));
    }
 
    @Override
@@ -79,6 +77,7 @@ public abstract class BaseProfitBricksRequestBinder<T> implements MapBinder {
       return fromRequest;
    }
    
+   @SuppressWarnings("unchecked")
    protected <R extends HttpRequest> R genRequest(String path, R fromRequest) {          
       R request = (R) fromRequest.toBuilder()
          .replacePath(endpointSupplier.get().getPath() + path)

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/snapshot/UpdateSnapshotRequestBinder.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/snapshot/UpdateSnapshotRequestBinder.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/snapshot/UpdateSnapshotRequestBinder.java
index 1db1cb6..b13849c 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/snapshot/UpdateSnapshotRequestBinder.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/snapshot/UpdateSnapshotRequestBinder.java
@@ -84,6 +84,7 @@ public class UpdateSnapshotRequestBinder extends BaseProfitBricksRequestBinder<S
       return jsonBinder.toJson(requestBuilder);
    }
 
+   @SuppressWarnings("unchecked")
    @Override
    protected <R extends HttpRequest> R createRequest(R fromRequest, String payload) {              
       R request = (R) fromRequest.toBuilder().replacePath(String.format("/rest/snapshots/%s", snapshotId)).build();

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/CreateSnapshotRequestBinder.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/CreateSnapshotRequestBinder.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/CreateSnapshotRequestBinder.java
index bd47ed9..1958ca4 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/CreateSnapshotRequestBinder.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/CreateSnapshotRequestBinder.java
@@ -58,6 +58,7 @@ public class CreateSnapshotRequestBinder extends BaseProfitBricksRequestBinder<V
       return "";
    }
 
+   @SuppressWarnings("unchecked")
    @Override
    protected <R extends HttpRequest> R createRequest(R fromRequest, String payload) {
       fromRequest = super.createRequest(fromRequest, payload);

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/RestoreSnapshotRequestBinder.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/RestoreSnapshotRequestBinder.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/RestoreSnapshotRequestBinder.java
index 999aec8..88428b0 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/RestoreSnapshotRequestBinder.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/volume/RestoreSnapshotRequestBinder.java
@@ -56,6 +56,7 @@ public class RestoreSnapshotRequestBinder extends BaseProfitBricksRequestBinder<
       return "";
    }
    
+   @SuppressWarnings("unchecked")
    @Override
    protected <R extends HttpRequest> R createRequest(R fromRequest, String payload) {
       fromRequest = super.createRequest(fromRequest, payload);

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/ProfitBricksComputeServiceAdapter.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/ProfitBricksComputeServiceAdapter.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/ProfitBricksComputeServiceAdapter.java
index f7f4145..be34f3f 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/ProfitBricksComputeServiceAdapter.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/ProfitBricksComputeServiceAdapter.java
@@ -17,35 +17,32 @@
 package org.apache.jclouds.profitbricks.rest.compute;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import com.google.common.base.Predicate;
 import static com.google.common.base.Strings.isNullOrEmpty;
-import com.google.common.base.Supplier;
-import com.google.common.base.Throwables;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
 import static com.google.common.collect.Iterables.contains;
 import static com.google.common.collect.Iterables.filter;
-import com.google.common.collect.Lists;
 import static com.google.common.util.concurrent.Futures.getUnchecked;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.inject.Inject;
 import static java.lang.String.format;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_NIC;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_SERVER;
+import static org.jclouds.Constants.PROPERTY_USER_THREADS;
+import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
+import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
+
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Callable;
+
 import javax.annotation.Resource;
 import javax.inject.Named;
 import javax.inject.Singleton;
+
 import org.apache.jclouds.profitbricks.rest.ProfitBricksApi;
 import org.apache.jclouds.profitbricks.rest.compute.concurrent.ProvisioningJob;
 import org.apache.jclouds.profitbricks.rest.compute.concurrent.ProvisioningManager;
 import org.apache.jclouds.profitbricks.rest.compute.function.ProvisionableToImage;
 import org.apache.jclouds.profitbricks.rest.compute.strategy.TemplateWithDataCenter;
-import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER;
-import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_NIC;
-import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_SERVER;
 import org.apache.jclouds.profitbricks.rest.domain.DataCenter;
 import org.apache.jclouds.profitbricks.rest.domain.Image;
 import org.apache.jclouds.profitbricks.rest.domain.Lan;
@@ -62,10 +59,8 @@ import org.apache.jclouds.profitbricks.rest.ids.NicRef;
 import org.apache.jclouds.profitbricks.rest.ids.ServerRef;
 import org.apache.jclouds.profitbricks.rest.ids.VolumeRef;
 import org.apache.jclouds.profitbricks.rest.util.Passwords;
-import static org.jclouds.Constants.PROPERTY_USER_THREADS;
+import org.apache.jclouds.profitbricks.rest.util.Trackables;
 import org.jclouds.compute.ComputeServiceAdapter;
-import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
-import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
 import org.jclouds.compute.domain.Hardware;
 import org.jclouds.compute.domain.HardwareBuilder;
 import org.jclouds.compute.domain.Processor;
@@ -81,6 +76,17 @@ import org.jclouds.domain.LoginCredentials;
 import org.jclouds.logging.Logger;
 import org.jclouds.rest.ResourceNotFoundException;
 
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.inject.Inject;
+
 @Singleton
 public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<ServerInDataCenter, Hardware, Provisionable, Location> {
 
@@ -95,6 +101,7 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
    private final Predicate<ServerRef> waitServerUntilRunning;
    private final Predicate<ServerRef> waitServerUntilSuspended;
    private final Predicate<NicRef> waitNICUntilAvailable;
+   private final Trackables trackables;
    private final ListeningExecutorService executorService;
    private final ProvisioningJob.Factory jobFactory;
    private final ProvisioningManager provisioningManager;
@@ -111,6 +118,7 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
            @Named(TIMEOUT_NODE_RUNNING) Predicate<ServerRef> waitServerUntilRunning,
            @Named(TIMEOUT_NODE_SUSPENDED) Predicate<ServerRef> waitServerUntilSuspended,
            @Named(POLL_PREDICATE_NIC) Predicate<NicRef> waitNICUntilAvailable,
+           Trackables trackables,
            ProvisioningJob.Factory jobFactory,
            ProvisioningManager provisioningManager) {
       this.api = api;
@@ -120,6 +128,7 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
       this.waitNICUntilAvailable = waitNICUntilAvailable;
       this.waitServerUntilSuspended = waitServerUntilSuspended;
       this.waitServerUntilRunning = waitServerUntilRunning;
+      this.trackables = trackables;
       this.executorService = executorService;
       this.jobFactory = jobFactory;
       this.provisioningManager = provisioningManager;
@@ -165,16 +174,16 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
                     size(volume.getSize().intValue()).
                     type(VolumeType.HDD);
 
-            String volumeId = (String) provisioningManager.provision(jobFactory.create(dataCenterId, new Supplier<Object>() {
-
+            org.apache.jclouds.profitbricks.rest.domain.Volume vol = (org.apache.jclouds.profitbricks.rest.domain.Volume) provisioningManager
+                  .provision(jobFactory.create(dataCenterId, new Supplier<Object>() {
                @Override
                public Object get() {
-                  return api.volumeApi().createVolume(request.build()).id();
+                  return api.volumeApi().createVolume(request.build());
                }
             }));
 
-            volumeIds.add(volumeId);
-            logger.trace(">> provisioning complete for volume. returned id='%s'", volumeId);
+            volumeIds.add(vol.id());
+            logger.trace(">> provisioning complete for volume. returned id='%s'", vol.id());
          } catch (Exception ex) {
             if (i - 1 == 1) // if first volume (one with image) provisioning fails; stop method
             {
@@ -188,7 +197,7 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
       waitVolumeUntilAvailable.apply(VolumeRef.create(dataCenterId, volumeBootDeviceId));
 
       // provision server
-      final String serverId;
+      final Server server;
       Double cores = ComputeServiceUtils.getCores(hardware);
 
       Server.BootVolume bootVolume = Server.BootVolume.create(volumeBootDeviceId);
@@ -204,14 +213,14 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
 
          logger.trace("<< provisioning server '%s'", serverRequest);
 
-         serverId = (String) provisioningManager.provision(jobFactory.create(dataCenterId, new Supplier<Object>() {
+         server = (Server) provisioningManager.provision(jobFactory.create(dataCenterId, new Supplier<Object>() {
 
             @Override
             public Object get() {
-               return api.serverApi().createServer(serverRequest).id();
+               return api.serverApi().createServer(serverRequest);
             }
          }));
-         logger.trace(">> provisioning complete for server. returned id='%s'", serverId);
+         logger.trace(">> provisioning complete for server. returned id='%s'", server.id());
 
       } catch (Exception ex) {
          logger.error(ex, ">> failed to provision server. rollbacking..");
@@ -219,17 +228,18 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
          throw Throwables.propagate(ex);
       }
 
-      waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, serverId));
+      waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, server.id()));
       waitDcUntilAvailable.apply(dataCenterId);
 
       //attach bootVolume to Server
-      api.serverApi().attachVolume(Server.Request.attachVolumeBuilder()
+      org.apache.jclouds.profitbricks.rest.domain.Volume volume = api.serverApi().attachVolume(Server.Request.attachVolumeBuilder()
               .dataCenterId(dataCenterId)
-              .serverId(serverId)
+              .serverId(server.id())
               .volumeId(bootVolume.id())
               .build());
 
-      waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, serverId));
+      trackables.waitUntilRequestCompleted(volume);
+      waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, server.id()));
       waitDcUntilAvailable.apply(dataCenterId);
 
       //fetch an existing lan and creat if non was found
@@ -252,6 +262,7 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
                  .isPublic(Boolean.TRUE)
                  .name("lan " + name)
                  .build());
+         trackables.waitUntilRequestCompleted(lan);
       }
 
       //add a NIC to the server
@@ -271,19 +282,20 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
               .dhcp(Boolean.TRUE)
               .lan(lanId)
               .firewallActive(Boolean.FALSE)
-              .serverId(serverId).
+              .serverId(server.id()).
               build());
-
-      waitNICUntilAvailable.apply(NicRef.create(dataCenterId, serverId, nic.id()));
+      
+      trackables.waitUntilRequestCompleted(nic);
+      waitNICUntilAvailable.apply(NicRef.create(dataCenterId, server.id(), nic.id()));
       waitDcUntilAvailable.apply(dataCenterId);
-      waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, serverId));
+      waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, server.id()));
 
       //connect the rest of volumes to server;delete if fails
       final int volumeCount = volumeIds.size();
       for (int j = 1; j < volumeCount; j++) { // skip first; already connected
          final String volumeId = volumeIds.get(j);
          try {
-            logger.trace("<< connecting volume '%s' to server '%s'", volumeId, serverId);
+            logger.trace("<< connecting volume '%s' to server '%s'", volumeId, server.id());
             provisioningManager.provision(jobFactory.create(group, new Supplier<Object>() {
 
                @Override
@@ -291,7 +303,7 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
                   return api.serverApi().attachVolume(
                           Server.Request.attachVolumeBuilder()
                           .dataCenterId(dataCenterId)
-                          .serverId(serverId)
+                          .serverId(server.id())
                           .volumeId(volumeId)
                           .build()
                   );
@@ -304,8 +316,8 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
                // delete unconnected volume
                logger.warn(ex, ">> failed to connect volume '%s'. deleting..", volumeId);
                destroyVolume(volumeId, dataCenterId);
-               logger.warn(ex, ">> rolling back server..", serverId);
-               destroyServer(serverId, dataCenterId);
+               logger.warn(ex, ">> rolling back server..", server.id());
+               destroyServer(server.id(), dataCenterId);
                throw ex;
             } catch (Exception ex1) {
                logger.error(ex, ">> failed to rollback");
@@ -313,17 +325,17 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
          }
       }
       waitDcUntilAvailable.apply(dataCenterId);
-      waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, serverId));
+      waitServerUntilAvailable.apply(ServerRef.create(dataCenterId, server.id()));
 
       LoginCredentials serverCredentials = LoginCredentials.builder()
               .user(loginUser)
               .password(password)
               .build();
 
-      String serverInDataCenterId = DataCenterAndId.fromDataCenterAndId(dataCenterId, serverId).slashEncode();
-      ServerInDataCenter server = getNode(serverInDataCenterId);
+      String serverInDataCenterId = DataCenterAndId.fromDataCenterAndId(dataCenterId, server.id()).slashEncode();
+      ServerInDataCenter serverInDatacenter = getNode(serverInDataCenterId);
 
-      return new NodeAndInitialCredentials<ServerInDataCenter>(server, serverInDataCenterId, serverCredentials);
+      return new NodeAndInitialCredentials<ServerInDataCenter>(serverInDatacenter, serverInDataCenterId, serverCredentials);
    }
 
    @Override
@@ -385,7 +397,11 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
 
       });
 
-      return Iterables.concat(getUnchecked(images), getUnchecked(snapshots));
+      ImmutableList.Builder<Provisionable> provisionables = ImmutableList.builder();
+      provisionables.addAll(getUnchecked(images));
+      provisionables.addAll(getUnchecked(snapshots));
+      
+      return provisionables.build();
    }
 
    @Override
@@ -449,10 +465,10 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
       // Fail pre-emptively if not found
       final ServerInDataCenter node = getRequiredNode(id);
       provisioningManager.provision(jobFactory.create(datacenterAndId.getDataCenter(), new Supplier<Object>() {
-
          @Override
          public Object get() {
-            api.serverApi().rebootServer(datacenterAndId.getDataCenter(), datacenterAndId.getId());
+            URI requestStatusURI = api.serverApi().rebootServer(datacenterAndId.getDataCenter(), datacenterAndId.getId());
+            trackables.waitUntilRequestCompleted(requestStatusURI);
             waitServerUntilRunning.apply(ServerRef.create(datacenterAndId.getDataCenter(), datacenterAndId.getId()));
             return node;
          }
@@ -468,10 +484,10 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
       }
 
       provisioningManager.provision(jobFactory.create(datacenterAndId.getDataCenter(), new Supplier<Object>() {
-
          @Override
          public Object get() {
-            api.serverApi().startServer(datacenterAndId.getDataCenter(), datacenterAndId.getId());
+            URI requestStatusURI = api.serverApi().startServer(datacenterAndId.getDataCenter(), datacenterAndId.getId());
+            trackables.waitUntilRequestCompleted(requestStatusURI);
             waitServerUntilRunning.apply(ServerRef.create(datacenterAndId.getDataCenter(), datacenterAndId.getId()));
             return node;
          }
@@ -490,7 +506,8 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
       provisioningManager.provision(jobFactory.create(datacenterAndId.getDataCenter(), new Supplier<Object>() {
          @Override
          public Object get() {
-            api.serverApi().stopServer(datacenterAndId.getDataCenter(), datacenterAndId.getId());
+            URI requestStatusURI = api.serverApi().stopServer(datacenterAndId.getDataCenter(), datacenterAndId.getId());
+            trackables.waitUntilRequestCompleted(requestStatusURI);
             waitServerUntilSuspended.apply(ServerRef.create(datacenterAndId.getDataCenter(), datacenterAndId.getId()));
             return node;
          }
@@ -527,11 +544,10 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
       try {
          logger.trace("<< deleting server with id=%s", serverId);
          provisioningManager.provision(jobFactory.create(dataCenterId, new Supplier<Object>() {
-
             @Override
             public Object get() {
-               api.serverApi().deleteServer(dataCenterId, serverId);
-
+               URI requestStatusURI = api.serverApi().deleteServer(dataCenterId, serverId);
+               trackables.waitUntilRequestCompleted(requestStatusURI);
                return serverId;
             }
          }));
@@ -554,8 +570,8 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
 
             @Override
             public Object get() {
-               api.volumeApi().deleteVolume(dataCenterId, volumeId);
-
+               URI requestStatusURI = api.volumeApi().deleteVolume(dataCenterId, volumeId);
+               trackables.waitUntilRequestCompleted(requestStatusURI);
                return volumeId;
             }
          }));

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/concurrent/ProvisioningJob.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/concurrent/ProvisioningJob.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/concurrent/ProvisioningJob.java
index af089fa..95d02ad 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/concurrent/ProvisioningJob.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/concurrent/ProvisioningJob.java
@@ -22,27 +22,31 @@ import java.util.concurrent.Callable;
 
 import javax.inject.Named;
 
+import org.apache.jclouds.profitbricks.rest.domain.Trackable;
+import org.apache.jclouds.profitbricks.rest.util.Trackables;
+
 import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
 import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER;
 
-public class ProvisioningJob implements Callable {
+public class ProvisioningJob implements Callable<Object> {
 
    public interface Factory {
-
       ProvisioningJob create(String group, Supplier<Object> operation);
    }
 
    private final Predicate<String> waitDataCenterUntilReady;
    private final String group;
    private final Supplier<Object> operation;
+   private final Trackables trackables;
 
    @Inject
-   ProvisioningJob(@Named(POLL_PREDICATE_DATACENTER) Predicate<String> waitDataCenterUntilReady,
-           @Assisted String group, @Assisted Supplier<Object> operation) {
+   ProvisioningJob(@Named(POLL_PREDICATE_DATACENTER) Predicate<String> waitDataCenterUntilReady, Trackables trackables,
+         @Assisted String group, @Assisted Supplier<Object> operation) {
       this.waitDataCenterUntilReady = waitDataCenterUntilReady;
+      this.trackables = trackables;
       this.group = checkNotNull(group, "group cannot be null");
       this.operation = checkNotNull(operation, "operation cannot be null");
    }
@@ -51,6 +55,9 @@ public class ProvisioningJob implements Callable {
    public Object call() throws Exception {
       waitDataCenterUntilReady.apply(group);
       Object obj = operation.get();
+      if (obj instanceof Trackable) {
+         trackables.waitUntilRequestCompleted((Trackable) obj);
+      }
       waitDataCenterUntilReady.apply(group);
 
       return obj;

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/config/ProfitBricksComputeServiceContextModule.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/config/ProfitBricksComputeServiceContextModule.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/config/ProfitBricksComputeServiceContextModule.java
index 15f2112..b244fb2 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/config/ProfitBricksComputeServiceContextModule.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/config/ProfitBricksComputeServiceContextModule.java
@@ -73,6 +73,7 @@ import static org.jclouds.util.Predicates2.retry;
 public class ProfitBricksComputeServiceContextModule extends
         ComputeServiceAdapterContextModule<ServerInDataCenter, Hardware, Provisionable, Location> {
 
+   @SuppressWarnings("unchecked")
    @Override
    protected void configure() {
       super.configure();

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ProvisionableToImage.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ProvisionableToImage.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ProvisionableToImage.java
index 3071b92..bf195a1 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ProvisionableToImage.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ProvisionableToImage.java
@@ -16,17 +16,14 @@
  */
 package org.apache.jclouds.profitbricks.rest.compute.function;
 
-import com.google.common.base.Function;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.base.Strings;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableMap;
 import static com.google.common.collect.Iterables.find;
-import com.google.inject.Inject;
+import static org.jclouds.location.predicates.LocationPredicates.idEquals;
+
 import java.util.Set;
 import java.util.regex.Pattern;
-import static org.apache.jclouds.profitbricks.rest.domain.Image.Type.CDROM;
+
 import org.apache.jclouds.profitbricks.rest.domain.LicenceType;
 import org.apache.jclouds.profitbricks.rest.domain.Provisionable;
 import org.apache.jclouds.profitbricks.rest.domain.Snapshot;
@@ -36,7 +33,12 @@ import org.jclouds.compute.domain.ImageBuilder;
 import org.jclouds.compute.domain.OperatingSystem;
 import org.jclouds.compute.domain.OsFamily;
 import org.jclouds.domain.Location;
-import static org.jclouds.location.predicates.LocationPredicates.idEquals;
+
+import com.google.common.base.Function;
+import com.google.common.base.Strings;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Inject;
 
 public class ProvisionableToImage implements Function<Provisionable, Image> {
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ServerInDataCenterToNodeMetadata.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ServerInDataCenterToNodeMetadata.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ServerInDataCenterToNodeMetadata.java
index e7f0cf0..9de3371 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ServerInDataCenterToNodeMetadata.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/function/ServerInDataCenterToNodeMetadata.java
@@ -163,6 +163,8 @@ public class ServerInDataCenterToNodeMetadata implements Function<ServerInDataCe
                        .description(OsFamily.LINUX.value())
                        .family(OsFamily.LINUX)
                        .build();
+            default:
+               break;
          }
       }
       return OperatingSystem.builder()

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/strategy/AssignDataCenterToTemplate.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/strategy/AssignDataCenterToTemplate.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/strategy/AssignDataCenterToTemplate.java
index 445f6c9..8af5d12 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/strategy/AssignDataCenterToTemplate.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/compute/strategy/AssignDataCenterToTemplate.java
@@ -16,22 +16,21 @@
  */
 package org.apache.jclouds.profitbricks.rest.compute.strategy;
 
-import com.google.common.annotations.Beta;
-import com.google.common.base.Predicate;
 import static com.google.common.collect.Iterables.find;
-import com.google.common.collect.Multimap;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER;
+import static org.jclouds.Constants.PROPERTY_USER_THREADS;
+
 import java.util.Map;
 import java.util.Set;
+
 import javax.annotation.Resource;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
+
 import org.apache.jclouds.profitbricks.rest.ProfitBricksApi;
-import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER;
 import org.apache.jclouds.profitbricks.rest.domain.DataCenter;
-import static org.jclouds.Constants.PROPERTY_USER_THREADS;
+import org.apache.jclouds.profitbricks.rest.util.Trackables;
 import org.jclouds.compute.config.CustomizationResponse;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.Template;
@@ -43,6 +42,12 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
 import org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
 import org.jclouds.logging.Logger;
 
+import com.google.common.annotations.Beta;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Multimap;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+
 @Beta
 @Singleton
 public class AssignDataCenterToTemplate extends CreateNodesWithGroupEncodedIntoNameThenAddToSet {
@@ -53,6 +58,7 @@ public class AssignDataCenterToTemplate extends CreateNodesWithGroupEncodedIntoN
 
    private final ProfitBricksApi api;
    private final Predicate<String> waitDcUntilAvailable;
+   private final Trackables trackables;
 
    @Inject
    protected AssignDataCenterToTemplate(
@@ -61,11 +67,13 @@ public class AssignDataCenterToTemplate extends CreateNodesWithGroupEncodedIntoN
            GroupNamingConvention.Factory namingConvention,
            @Named(PROPERTY_USER_THREADS) ListeningExecutorService userExecutor,
            CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
-           ProfitBricksApi api, @Named(POLL_PREDICATE_DATACENTER) Predicate<String> waitDcUntilAvailable) {
+           ProfitBricksApi api, @Named(POLL_PREDICATE_DATACENTER) Predicate<String> waitDcUntilAvailable,
+           Trackables trackables) {
       super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor,
               customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
       this.api = api;
       this.waitDcUntilAvailable = waitDcUntilAvailable;
+      this.trackables = trackables;
    }
 
    @Override
@@ -89,7 +97,11 @@ public class AssignDataCenterToTemplate extends CreateNodesWithGroupEncodedIntoN
          String name = namingConvention.create().sharedNameForGroup(group);
          logger.info(">> no datacenter was found. Creating a new one named %s in %s...", name, template.getLocation()
                  .getId());
+         
          dataCenter = api.dataCenterApi().create(name, "desc,,,", template.getLocation().getId());
+         trackables.waitUntilRequestCompleted(dataCenter);
+
+         dataCenter = api.dataCenterApi().getDataCenter(dataCenter.id());
          waitDcUntilAvailable.apply(dataCenter.id());
       }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksHttpApiModule.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksHttpApiModule.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksHttpApiModule.java
index ef7b37e..8d69631 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksHttpApiModule.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksHttpApiModule.java
@@ -16,17 +16,29 @@
  */
 package org.apache.jclouds.profitbricks.rest.config;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.util.Predicates2.retry;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Singleton;
+
+import org.apache.jclouds.profitbricks.rest.ProfitBricksApi;
+import org.apache.jclouds.profitbricks.rest.compute.config.ProfitBricksComputeServiceContextModule.ComputeConstants;
+import org.apache.jclouds.profitbricks.rest.domain.RequestStatus;
+import org.apache.jclouds.profitbricks.rest.handlers.ProfitBricksHttpErrorHandler;
 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.json.config.GsonModule.DateAdapter;
+import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
 import org.jclouds.rest.ConfiguresHttpApi;
 import org.jclouds.rest.config.HttpApiModule;
 
-import org.apache.jclouds.profitbricks.rest.ProfitBricksApi;
-import org.apache.jclouds.profitbricks.rest.handlers.ProfitBricksHttpErrorHandler;
-import org.jclouds.json.config.GsonModule.DateAdapter;
-import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
+import com.google.common.base.Predicate;
+import com.google.inject.Provides;
 
 @ConfiguresHttpApi
 public class ProfitBricksHttpApiModule extends HttpApiModule<ProfitBricksApi> {
@@ -37,10 +49,38 @@ public class ProfitBricksHttpApiModule extends HttpApiModule<ProfitBricksApi> {
       bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ProfitBricksHttpErrorHandler.class);
       bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ProfitBricksHttpErrorHandler.class);
    }
-   
+
    @Override
    protected void configure() {
       super.configure();
       bind(DateAdapter.class).to(Iso8601DateAdapter.class);
    }
+
+   @Provides
+   @Singleton
+   Predicate<URI> provideRequestCompletedPredicate(final ProfitBricksApi api, ComputeConstants constants) {
+      return retry(new RequestCompletedPredicate(api), constants.pollTimeout(), constants.pollPeriod(),
+            constants.pollMaxPeriod(), TimeUnit.SECONDS);
+   }
+
+   private static class RequestCompletedPredicate implements Predicate<URI> {
+      private final ProfitBricksApi api;
+
+      private RequestCompletedPredicate(ProfitBricksApi api) {
+         this.api = checkNotNull(api, "api must not be null");
+      }
+
+      @Override
+      public boolean apply(URI uri) {
+         RequestStatus status = api.getRequestStatus(checkNotNull(uri, "uri"));
+         switch (status.metadata().status()) {
+            case DONE:
+            case FAILED:
+               return true;
+            default:
+               return false;
+         }
+      }
+
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/DataCenter.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/DataCenter.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/DataCenter.java
index b08c0aa..cd93ca1 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/DataCenter.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/DataCenter.java
@@ -21,7 +21,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
 @AutoValue
-public abstract class DataCenter {
+public abstract class DataCenter extends Trackable {
 
    public abstract String id();
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/FirewallRule.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/FirewallRule.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/FirewallRule.java
index 2a0ac1d..6f156f0 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/FirewallRule.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/FirewallRule.java
@@ -22,7 +22,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
 @AutoValue
-public abstract class FirewallRule {
+public abstract class FirewallRule extends Trackable {
 
     public abstract String id();
     

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Image.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Image.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Image.java
index f1135be..e9372c4 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Image.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Image.java
@@ -22,7 +22,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
 @AutoValue
-public abstract class Image implements Provisionable {
+public abstract class Image extends Trackable implements Provisionable {
 
    public enum Type {
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/IpBlock.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/IpBlock.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/IpBlock.java
index 6836477..3434b09 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/IpBlock.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/IpBlock.java
@@ -22,7 +22,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
 @AutoValue
-public abstract class IpBlock {
+public abstract class IpBlock extends Trackable {
 
    public abstract String id();
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Lan.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Lan.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Lan.java
index eea8afe..2aeb60f 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Lan.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Lan.java
@@ -22,7 +22,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
 @AutoValue
-public abstract class Lan {
+public abstract class Lan extends Trackable {
 
    public abstract String id();
    

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Nic.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Nic.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Nic.java
index 10b75da..4071dad 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Nic.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Nic.java
@@ -24,7 +24,7 @@ import static com.google.common.collect.ImmutableList.copyOf;
 import org.jclouds.javax.annotation.Nullable;
 
 @AutoValue
-public abstract class Nic {
+public abstract class Nic extends Trackable {
 
    public abstract String id();
    

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/RequestStatus.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/RequestStatus.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/RequestStatus.java
new file mode 100644
index 0000000..e7ba5f2
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/RequestStatus.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jclouds.profitbricks.rest.domain;
+
+import java.util.List;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Enums;
+import com.google.common.collect.ImmutableList;
+
+@AutoValue
+public abstract class RequestStatus {
+
+   public static enum Status {
+      DONE, FAILED, RUNNING, UNRECOGNIZED;
+
+      public static Status fromValue(String value) {
+         return Enums.getIfPresent(Status.class, value).or(UNRECOGNIZED);
+      }
+   }
+   
+   public abstract String id();
+   public abstract String type();
+   public abstract String href();
+   public abstract Metadata metadata();
+   
+   RequestStatus() { }
+   
+   @SerializedNames({"id", "type", "href", "metadata"})
+   public static RequestStatus create(String id, String type, String href, Metadata metadata) {
+      return new AutoValue_RequestStatus(id, type, href, metadata);
+   }
+   
+   @AutoValue
+   public abstract static class Metadata {
+      public abstract Status status();
+      public abstract String message();
+      public abstract String etag();
+      public abstract List<TargetEntity> targets();
+      
+      Metadata() { }
+      
+      @SerializedNames({"status", "message", "etag", "targets"})
+      public static Metadata create(Status status, String message, String etag, List<TargetEntity> targets) {
+         return new AutoValue_RequestStatus_Metadata(status, message, etag, ImmutableList.copyOf(targets));
+      }
+      
+      @AutoValue
+      public abstract static class TargetEntity {
+         public abstract Status status();
+         public abstract Target target();
+         
+         TargetEntity() { }
+         
+         @SerializedNames({"status", "target"})
+         public static TargetEntity create(Status status, Target target) {
+            return new AutoValue_RequestStatus_Metadata_TargetEntity(status, target);
+         }
+         
+         @AutoValue
+         public abstract static class Target {
+            public abstract String id();
+            public abstract String type();
+            public abstract String href();
+            
+            Target() { }
+            
+            @SerializedNames({"id", "type", "href"})
+            public static Target create(String id, String type, String href) {
+               return new AutoValue_RequestStatus_Metadata_TargetEntity_Target(id, type, href);
+            }
+         }
+      }
+   }
+   
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Server.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Server.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Server.java
index 833c869..1b8b01b 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Server.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Server.java
@@ -23,7 +23,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
 @AutoValue
-public abstract class Server {
+public abstract class Server extends Trackable {
 
    public abstract String id();
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Snapshot.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Snapshot.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Snapshot.java
index 5fd1abc..be65452 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Snapshot.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Snapshot.java
@@ -22,7 +22,7 @@ import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
 @AutoValue
-public abstract class Snapshot implements Provisionable {
+public abstract class Snapshot extends Trackable implements Provisionable {
 
    public abstract String id();
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Trackable.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Trackable.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Trackable.java
new file mode 100644
index 0000000..ce89175
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Trackable.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jclouds.profitbricks.rest.domain;
+
+import java.net.URI;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.common.base.Optional;
+
+/**
+ * Designates objects which status that can be tracked using a request status
+ * URI reference.
+ */
+public class Trackable {
+
+   protected transient Optional<URI> requestStatusUri;
+
+   public Optional<URI> requestStatusUri() {
+      return requestStatusUri;
+   }
+
+   public void setRequestStatusUri(@Nullable URI requestStatusUri) {
+      this.requestStatusUri = Optional.fromNullable(requestStatusUri);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Volume.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Volume.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Volume.java
index bab0909..e0109f0 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Volume.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Volume.java
@@ -25,7 +25,7 @@ import static com.google.common.base.Preconditions.checkArgument;
 import java.util.Set;
 
 @AutoValue
-public abstract class Volume {
+public abstract class Volume extends Trackable {
 
     public abstract String id();
     

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApi.java
index 5df496d..34ce39f 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApi.java
@@ -17,14 +17,13 @@
 package org.apache.jclouds.profitbricks.rest.features;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
-import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.rest.annotations.RequestFilters;
+
 import java.io.Closeable;
+import java.net.URI;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+
 import javax.inject.Named;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -32,23 +31,29 @@ import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+
 import org.apache.jclouds.profitbricks.rest.domain.DataCenter;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
-import org.apache.jclouds.profitbricks.rest.features.DataCenterApi.DataCenterParser;
+import org.apache.jclouds.profitbricks.rest.functions.ParseRequestStatusURI;
+import org.apache.jclouds.profitbricks.rest.functions.RequestStatusURIParser;
 import org.jclouds.Fallbacks;
 import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
 import org.jclouds.Fallbacks.NullOnNotFoundOr404;
 import org.jclouds.http.HttpRequest;
-import org.jclouds.http.functions.ParseJson;
+import org.jclouds.http.filters.BasicAuthentication;
 import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
 import org.jclouds.rest.annotations.PATCH;
 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.binders.BindToJsonPayload;
 
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
 @Path("/datacenters")
 @RequestFilters(BasicAuthentication.class)
 public interface DataCenterApi extends Closeable {
@@ -110,11 +115,12 @@ public interface DataCenterApi extends Closeable {
    @DELETE
    @Path("/{id}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void delete(@PathParam("id") String id);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI delete(@PathParam("id") String id);
    
-   static final class DataCenterParser extends ParseJson<DataCenter> {
-      @Inject DataCenterParser(Json json) {
-         super(json, TypeLiteral.get(DataCenter.class));
+   static final class DataCenterParser extends RequestStatusURIParser<DataCenter> {
+      @Inject DataCenterParser(Json json, ParseRequestStatusURI parseRequestStatusURI) {
+         super(json, TypeLiteral.get(DataCenter.class), parseRequestStatusURI);
       }
    }
    
@@ -134,7 +140,6 @@ public interface DataCenterApi extends Closeable {
 
       @Override
       public <R extends HttpRequest> R bindToRequest(R request, Object payload) {
-         
          Map<String, Object> params = new HashMap<String, Object>();
          params.put("properties", payload);
          

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/FirewallApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/FirewallApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/FirewallApi.java
index 984c6f7..82344cd 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/FirewallApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/FirewallApi.java
@@ -16,13 +16,13 @@
  */
 package org.apache.jclouds.profitbricks.rest.features;
 
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Type;
+import java.net.URI;
 import java.util.List;
+
 import javax.inject.Named;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -30,15 +30,17 @@ import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+
 import org.apache.jclouds.profitbricks.rest.binder.firewall.CreateFirewallRuleRequestBinder;
 import org.apache.jclouds.profitbricks.rest.binder.firewall.UpdateFirewallRuleRequestBinder;
 import org.apache.jclouds.profitbricks.rest.domain.FirewallRule;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
+import org.apache.jclouds.profitbricks.rest.functions.ParseRequestStatusURI;
+import org.apache.jclouds.profitbricks.rest.functions.RequestStatusURIParser;
 import org.apache.jclouds.profitbricks.rest.util.ParseId;
 import org.jclouds.Fallbacks;
 import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
 import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
@@ -49,6 +51,9 @@ import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.util.Strings2;
 
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
 @Path("/datacenters/{dataCenterId}/servers/{serverId}/nics/{nicId}/firewallrules")
 @RequestFilters(BasicAuthentication.class)
 public interface FirewallApi extends Closeable {
@@ -96,17 +101,19 @@ public interface FirewallApi extends Closeable {
    @DELETE
    @Path("/{firewallRuleId}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void delete(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("nicId") String nicId, @PathParam("firewallRuleId") String firewallRuleId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI delete(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("nicId") String nicId, @PathParam("firewallRuleId") String firewallRuleId);
    
-   static final class FirewallRuleParser extends ParseJson<FirewallRule> {
+   static final class FirewallRuleParser extends RequestStatusURIParser<FirewallRule> {
       
       private final ParseId parseService;
             
-      @Inject FirewallRuleParser(Json json, ParseId parseId) {
-         super(json, TypeLiteral.get(FirewallRule.class));
+      @Inject FirewallRuleParser(Json json, ParseId parseId, ParseRequestStatusURI parseRequestStatusURI) {
+         super(json, TypeLiteral.get(FirewallRule.class), parseRequestStatusURI);
          this.parseService = parseId;
       }
-      
+
+      @SuppressWarnings("unchecked")
       @Override      
       public <V> V apply(InputStream stream, Type type) throws IOException {
          try {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ImageApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ImageApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ImageApi.java
index 74a7e72..21e0464 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ImageApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ImageApi.java
@@ -16,26 +16,30 @@
  */
 package org.apache.jclouds.profitbricks.rest.features;
 
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
 import java.io.Closeable;
 import java.util.List;
+
 import javax.inject.Named;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+
 import org.apache.jclouds.profitbricks.rest.domain.Image;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
+import org.apache.jclouds.profitbricks.rest.functions.ParseRequestStatusURI;
+import org.apache.jclouds.profitbricks.rest.functions.RequestStatusURIParser;
 import org.jclouds.Fallbacks;
 import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
 import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
 @Path("/images")
 @RequestFilters(BasicAuthentication.class)
 public interface ImageApi extends Closeable {
@@ -67,9 +71,9 @@ public interface ImageApi extends Closeable {
    @Fallback(Fallbacks.NullOnNotFoundOr404.class)
    Image getImage(@PathParam("imageId") String imageId, DepthOptions options);
    
-   static final class ImageParser extends ParseJson<Image> {
-      @Inject ImageParser(Json json) {
-         super(json, TypeLiteral.get(Image.class));
+   static final class ImageParser extends RequestStatusURIParser<Image> {
+      @Inject ImageParser(Json json, ParseRequestStatusURI parseRequestStatusURI) {
+         super(json, TypeLiteral.get(Image.class), parseRequestStatusURI);
       }
    }
    

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/IpBlockApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/IpBlockApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/IpBlockApi.java
index d97d981..5b0d351 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/IpBlockApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/IpBlockApi.java
@@ -16,10 +16,10 @@
  */
 package org.apache.jclouds.profitbricks.rest.features;
 
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
 import java.io.Closeable;
+import java.net.URI;
 import java.util.List;
+
 import javax.inject.Named;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -27,12 +27,14 @@ import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+
 import org.apache.jclouds.profitbricks.rest.domain.IpBlock;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
+import org.apache.jclouds.profitbricks.rest.functions.ParseRequestStatusURI;
+import org.apache.jclouds.profitbricks.rest.functions.RequestStatusURIParser;
 import org.apache.jclouds.profitbricks.rest.util.ParseId;
 import org.jclouds.Fallbacks;
 import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.BinderParam;
 import org.jclouds.rest.annotations.Fallback;
@@ -41,6 +43,9 @@ import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.rest.binders.BindToJsonPayload;
 
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
 @Path("/ipblocks")
 @RequestFilters(BasicAuthentication.class)
 public interface IpBlockApi extends Closeable {
@@ -74,15 +79,16 @@ public interface IpBlockApi extends Closeable {
    @DELETE
    @Path("/{ipblockId}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void delete(@PathParam("ipblockId") String ipblockId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI delete(@PathParam("ipblockId") String ipblockId);
 
-   static final class IpBlockParser extends ParseJson<IpBlock> {
+   static final class IpBlockParser extends RequestStatusURIParser<IpBlock> {
 
       final ParseId parseService;
 
       @Inject
-      IpBlockParser(Json json, ParseId parseId) {
-         super(json, TypeLiteral.get(IpBlock.class));
+      IpBlockParser(Json json, ParseId parseId, ParseRequestStatusURI parseRequestStatusURI) {
+         super(json, TypeLiteral.get(IpBlock.class), parseRequestStatusURI);
          this.parseService = parseId;
       }
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/LanApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/LanApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/LanApi.java
index 3adec5b..8900475 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/LanApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/LanApi.java
@@ -16,13 +16,13 @@
  */
 package org.apache.jclouds.profitbricks.rest.features;
 
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Type;
+import java.net.URI;
 import java.util.List;
+
 import javax.inject.Named;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -30,15 +30,17 @@ import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+
 import org.apache.jclouds.profitbricks.rest.binder.lan.CreateLanRequestBinder;
 import org.apache.jclouds.profitbricks.rest.binder.lan.UpdateLanRequestBinder;
 import org.apache.jclouds.profitbricks.rest.domain.Lan;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
+import org.apache.jclouds.profitbricks.rest.functions.ParseRequestStatusURI;
+import org.apache.jclouds.profitbricks.rest.functions.RequestStatusURIParser;
 import org.apache.jclouds.profitbricks.rest.util.ParseId;
 import org.jclouds.Fallbacks;
 import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
 import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
@@ -49,6 +51,9 @@ import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.util.Strings2;
 
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
 @Path("/datacenters/{dataCenterId}/lans")
 @RequestFilters(BasicAuthentication.class)
 public interface LanApi extends Closeable {
@@ -97,17 +102,19 @@ public interface LanApi extends Closeable {
    @DELETE
    @Path("/{lanId}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void delete(@PathParam("dataCenterId") String dataCenterId, @PathParam("lanId") String lanId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI delete(@PathParam("dataCenterId") String dataCenterId, @PathParam("lanId") String lanId);
    
-   static final class LanParser extends ParseJson<Lan> {
+   static final class LanParser extends RequestStatusURIParser<Lan> {
             
       final ParseId parseService;
       
-      @Inject LanParser(Json json, ParseId parseId) {
-         super(json, TypeLiteral.get(Lan.class));
+      @Inject LanParser(Json json, ParseId parseId, ParseRequestStatusURI parseRequestStatusURI) {
+         super(json, TypeLiteral.get(Lan.class), parseRequestStatusURI);
          this.parseService = parseId;
       }
 
+      @SuppressWarnings("unchecked")
       @Override
       public <V> V apply(InputStream stream, Type type) throws IOException {
          try {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/NicApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/NicApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/NicApi.java
index 965ddad..0fc46d8 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/NicApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/NicApi.java
@@ -16,13 +16,13 @@
  */
 package org.apache.jclouds.profitbricks.rest.features;
 
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Type;
+import java.net.URI;
 import java.util.List;
+
 import javax.inject.Named;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -30,15 +30,17 @@ import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+
 import org.apache.jclouds.profitbricks.rest.binder.nic.CreateNicRequestBinder;
 import org.apache.jclouds.profitbricks.rest.binder.nic.UpdateNicRequestBinder;
 import org.apache.jclouds.profitbricks.rest.domain.Nic;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
+import org.apache.jclouds.profitbricks.rest.functions.ParseRequestStatusURI;
+import org.apache.jclouds.profitbricks.rest.functions.RequestStatusURIParser;
 import org.apache.jclouds.profitbricks.rest.util.ParseId;
 import org.jclouds.Fallbacks;
 import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
 import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
@@ -49,6 +51,9 @@ import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.util.Strings2;
 
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
 @Path("/datacenters/{dataCenterId}/servers/{serverId}/nics")
 @RequestFilters(BasicAuthentication.class)
 public interface NicApi extends Closeable {
@@ -97,17 +102,19 @@ public interface NicApi extends Closeable {
    @DELETE
    @Path("/{nicId}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void delete(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("nicId") String nicId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI delete(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("nicId") String nicId);
    
-   static final class NicParser extends ParseJson<Nic> {
+   static final class NicParser extends RequestStatusURIParser<Nic> {
       
       private final ParseId parseService;
             
-      @Inject NicParser(Json json, ParseId parseId) {
-         super(json, TypeLiteral.get(Nic.class));
+      @Inject NicParser(Json json, ParseId parseId, ParseRequestStatusURI parseRequestStatusURI) {
+         super(json, TypeLiteral.get(Nic.class), parseRequestStatusURI);
          this.parseService = parseId;
       }
       
+      @SuppressWarnings("unchecked")
       @Override      
       public <V> V apply(InputStream stream, Type type) throws IOException {
          try {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ServerApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ServerApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ServerApi.java
index 8813497..3987e59 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ServerApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ServerApi.java
@@ -16,13 +16,13 @@
  */
 package org.apache.jclouds.profitbricks.rest.features;
 
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Type;
+import java.net.URI;
 import java.util.List;
+
 import javax.inject.Named;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
@@ -30,6 +30,7 @@ import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+
 import org.apache.jclouds.profitbricks.rest.binder.server.AttachCdromRequestBinder;
 import org.apache.jclouds.profitbricks.rest.binder.server.AttachVolumeRequestBinder;
 import org.apache.jclouds.profitbricks.rest.binder.server.CreateServerRequestBinder;
@@ -38,11 +39,12 @@ import org.apache.jclouds.profitbricks.rest.domain.Image;
 import org.apache.jclouds.profitbricks.rest.domain.Server;
 import org.apache.jclouds.profitbricks.rest.domain.Volume;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
+import org.apache.jclouds.profitbricks.rest.functions.ParseRequestStatusURI;
+import org.apache.jclouds.profitbricks.rest.functions.RequestStatusURIParser;
 import org.apache.jclouds.profitbricks.rest.util.ParseId;
 import org.jclouds.Fallbacks;
 import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
 import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
@@ -53,6 +55,9 @@ import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 import org.jclouds.util.Strings2;
 
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
 @Path("/datacenters/{dataCenterId}/servers")
 @RequestFilters(BasicAuthentication.class)
 public interface ServerApi extends Closeable {
@@ -101,7 +106,8 @@ public interface ServerApi extends Closeable {
    @DELETE
    @Path("/{serverId}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void deleteServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI deleteServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
 
    @Named("server:volume:list")
    @GET
@@ -120,7 +126,8 @@ public interface ServerApi extends Closeable {
    @DELETE
    @Path("/{serverId}/volumes/{volumeId}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void detachVolume(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("volumeId") String volumeId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI detachVolume(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("volumeId") String volumeId);
 
    @Named("server:volume:get")
    @GET
@@ -146,7 +153,8 @@ public interface ServerApi extends Closeable {
    @DELETE
    @Path("/{serverId}/cdroms/{cdRomId}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void detachCdrom(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("cdRomId") String cdRomId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI detachCdrom(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("cdRomId") String cdRomId);
 
    @Named("server:cdrom:get")
    @GET
@@ -158,28 +166,32 @@ public interface ServerApi extends Closeable {
    @Named("server:reboot")
    @POST
    @Path("/{serverId}/reboot")
-   void rebootServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI rebootServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
 
    @Named("server:start")
    @POST
    @Path("/{serverId}/start")
-   void startServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI startServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
 
    @Named("server:stop")
    @POST
    @Path("/{serverId}/stop")
-   void stopServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI stopServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
 
-   static final class ServerParser extends ParseJson<Server> {
+   static final class ServerParser extends RequestStatusURIParser<Server> {
 
       final ParseId parseService;
 
       @Inject
-      ServerParser(Json json, ParseId parseId) {
-         super(json, TypeLiteral.get(Server.class));
+      ServerParser(Json json, ParseId parseId, ParseRequestStatusURI parseRequestStatusURI) {
+         super(json, TypeLiteral.get(Server.class), parseRequestStatusURI);
          this.parseService = parseId;
       }
 
+      @SuppressWarnings("unchecked")
       @Override
       public <V> V apply(InputStream stream, Type type) throws IOException {
          try {

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/c4e36e72/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/SnapshotApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/SnapshotApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/SnapshotApi.java
index 0877b48..fd134f5 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/SnapshotApi.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/SnapshotApi.java
@@ -16,23 +16,25 @@
  */
 package org.apache.jclouds.profitbricks.rest.features;
 
-import com.google.inject.Inject;
-import com.google.inject.TypeLiteral;
 import java.io.Closeable;
+import java.net.URI;
 import java.util.List;
+
 import javax.inject.Named;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+
 import org.apache.jclouds.profitbricks.rest.binder.snapshot.UpdateSnapshotRequestBinder;
 import org.apache.jclouds.profitbricks.rest.domain.Snapshot;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
+import org.apache.jclouds.profitbricks.rest.functions.ParseRequestStatusURI;
+import org.apache.jclouds.profitbricks.rest.functions.RequestStatusURIParser;
 import org.jclouds.Fallbacks;
 import org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
 import org.jclouds.http.filters.BasicAuthentication;
-import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 import org.jclouds.rest.annotations.Fallback;
 import org.jclouds.rest.annotations.MapBinder;
@@ -42,6 +44,9 @@ import org.jclouds.rest.annotations.RequestFilters;
 import org.jclouds.rest.annotations.ResponseParser;
 import org.jclouds.rest.annotations.SelectJson;
 
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+
 @Path("/snapshots")
 @RequestFilters(BasicAuthentication.class)
 public interface SnapshotApi extends Closeable {
@@ -84,12 +89,13 @@ public interface SnapshotApi extends Closeable {
    @DELETE
    @Path("/{snapshotId}")
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
-   void delete(@PathParam("snapshotId") String snapshotId);
+   @ResponseParser(ParseRequestStatusURI.class)
+   URI delete(@PathParam("snapshotId") String snapshotId);
 
       
-   static final class SnapshotParser extends ParseJson<Snapshot> {
-      @Inject SnapshotParser(Json json) {
-         super(json, TypeLiteral.get(Snapshot.class));
+   static final class SnapshotParser extends RequestStatusURIParser<Snapshot> {
+      @Inject SnapshotParser(Json json, ParseRequestStatusURI parseRequestStatusURI) {
+         super(json, TypeLiteral.get(Snapshot.class), parseRequestStatusURI);
       }
    }