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/02/09 10:39:56 UTC

[3/3] jclouds-labs git commit: Implemented Server Api

Implemented Server Api


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

Branch: refs/heads/master
Commit: cfb4311f2b09451add79b6dceff4c435c4249310
Parents: 35c68cd
Author: mirza-spc <mi...@stackpointcloud.com>
Authored: Wed Dec 23 09:33:41 2015 +0100
Committer: Ignasi Barrera <na...@apache.org>
Committed: Tue Feb 9 10:34:02 2016 +0100

----------------------------------------------------------------------
 profitbricks-rest/pom.xml                       |  12 -
 .../profitbricks/rest/ProfitBricksApi.java      |   5 +
 .../rest/ProfitBricksApiMetadata.java           |   5 +-
 .../rest/ProfitBricksProviderMetadata.java      |  13 +
 .../binder/BaseProfitBricksRequestBinder.java   |  73 ++
 .../binder/server/AttachCdromRequestBinder.java |  61 ++
 .../server/AttachVolumeRequestBinder.java       |  61 ++
 .../server/CreateServerRequestBinder.java       |  88 +++
 .../server/UpdateServerRequestBinder.java       |  71 ++
 .../config/ProfitBricksComputeProperties.java   |  35 +
 .../profitbricks/rest/domain/Firewall.java      | 135 ++++
 .../jclouds/profitbricks/rest/domain/Image.java | 110 +++
 .../profitbricks/rest/domain/Images.java        |  42 +
 .../profitbricks/rest/domain/LicenceType.java   |   5 +-
 .../profitbricks/rest/domain/Location.java      |  26 +-
 .../rest/domain/ProvisioningState.java          |  28 +
 .../profitbricks/rest/domain/Server.java        | 236 +++++-
 .../profitbricks/rest/domain/Volume.java        |   9 +-
 .../rest/features/DataCenterApi.java            |   1 -
 .../profitbricks/rest/features/ImageApi.java    |  39 +
 .../profitbricks/rest/features/ServerApi.java   | 194 +++++
 .../profitbricks/rest/features/VolumeApi.java   |  39 +
 .../profitbricks/rest/ids/ServerRef.java        |  31 +
 .../rest/util/ApiPredicatesModule.java          | 140 ++++
 .../jclouds/profitbricks/rest/util/ParseId.java |  58 ++
 .../profitbricks/rest/util/Preconditions.java   |  90 +++
 .../rest/features/DataCenterApiLiveTest.java    |  15 +-
 .../rest/features/DataCenterApiMockTest.java    |   5 +-
 .../rest/features/ServerApiLiveTest.java        | 215 ++++++
 .../rest/features/ServerApiMockTest.java        | 322 ++++++++
 .../internal/BaseProfitBricksApiMockTest.java   |   4 +
 .../rest/internal/BaseProfitBricksLiveTest.java | 121 ++-
 .../src/test/resources/server/cdrom.json        |  32 +
 .../src/test/resources/server/cdroms.json       |  39 +
 .../src/test/resources/server/get-depth-5.json  | 171 ++++
 .../src/test/resources/server/get.json          | 173 +++++
 .../src/test/resources/server/image.json        |  32 +
 .../src/test/resources/server/list-depth-5.json | 660 ++++++++++++++++
 .../src/test/resources/server/list.json         | 770 +++++++++++++++++++
 .../src/test/resources/server/volume.json       |  33 +
 .../src/test/resources/server/volumes.json      |  73 ++
 41 files changed, 4209 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/pom.xml
----------------------------------------------------------------------
diff --git a/profitbricks-rest/pom.xml b/profitbricks-rest/pom.xml
index 62288c5..d676d88 100644
--- a/profitbricks-rest/pom.xml
+++ b/profitbricks-rest/pom.xml
@@ -51,11 +51,6 @@
             <version>${jclouds.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.jclouds</groupId>
-            <artifactId>jclouds-compute</artifactId>
-            <version>${jclouds.version}</version>
-        </dependency>
-        <dependency>
             <groupId>com.google.auto.service</groupId>
             <artifactId>auto-service</artifactId>
             <scope>provided</scope>
@@ -79,13 +74,6 @@
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.jclouds</groupId>
-            <artifactId>jclouds-compute</artifactId>
-            <version>${jclouds.version}</version>
-            <type>test-jar</type>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.jclouds.driver</groupId>
             <artifactId>jclouds-sshj</artifactId>
             <version>${jclouds.version}</version>

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/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 ed163da..977fbc7 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
@@ -20,6 +20,7 @@ package org.apache.jclouds.profitbricks.rest;
 import com.google.common.annotations.Beta;
 import java.io.Closeable;
 import org.apache.jclouds.profitbricks.rest.features.DataCenterApi;
+import org.apache.jclouds.profitbricks.rest.features.ServerApi;
 import org.jclouds.rest.annotations.Delegate;
 
 @Beta
@@ -27,4 +28,8 @@ public interface ProfitBricksApi extends Closeable {
    
    @Delegate
    DataCenterApi dataCenterApi();
+   
+   @Delegate
+   ServerApi serverApi();
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApiMetadata.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApiMetadata.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApiMetadata.java
index 3721919..e55d944 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApiMetadata.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksApiMetadata.java
@@ -20,10 +20,9 @@ import com.google.common.collect.ImmutableSet;
 import com.google.inject.Module;
 import java.net.URI;
 import java.util.Properties;
+import org.apache.jclouds.profitbricks.rest.util.ApiPredicatesModule;
 import org.apache.jclouds.profitbricks.rest.config.ProfitBricksHttpApiModule;
-import org.jclouds.compute.ComputeServiceContext;
 import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule;
-import static org.jclouds.reflect.Reflection2.typeToken;
 import org.jclouds.rest.internal.BaseHttpApiMetadata;
 
 public class ProfitBricksApiMetadata extends BaseHttpApiMetadata<ProfitBricksApi> {
@@ -56,10 +55,10 @@ public class ProfitBricksApiMetadata extends BaseHttpApiMetadata<ProfitBricksApi
             .documentation(URI.create("https://devops.profitbricks.com/api/rest/"))
             .defaultEndpoint("https://api.profitbricks.com/rest/")
             .defaultProperties(ProfitBricksApiMetadata.defaultProperties())
-            .view(typeToken(ComputeServiceContext.class))
             .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
                .add(OkHttpCommandExecutorServiceModule.class)
                .add(ProfitBricksHttpApiModule.class)
+               .add(ApiPredicatesModule.class)
                .build());
       }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksProviderMetadata.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksProviderMetadata.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksProviderMetadata.java
index bd12d38..feb31c9 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksProviderMetadata.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ProfitBricksProviderMetadata.java
@@ -19,7 +19,12 @@ package org.apache.jclouds.profitbricks.rest;
 import com.google.auto.service.AutoService;
 import java.net.URI;
 import java.util.Properties;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_MAX_PERIOD;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PERIOD;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_TIMEOUT;
+import static org.jclouds.Constants.PROPERTY_CONNECTION_TIMEOUT;
 import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
+import static org.jclouds.Constants.PROPERTY_SO_TIMEOUT;
 import static org.jclouds.location.reference.LocationConstants.ISO3166_CODES;
 import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGION;
 import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
@@ -63,6 +68,14 @@ public class ProfitBricksProviderMetadata extends BaseProviderMetadata {
       properties.setProperty(PROPERTY_ZONE + ".LAS." + ISO3166_CODES, "US-NV");
       properties.setProperty(PROPERTY_ZONE + ".LASDEV." + ISO3166_CODES, "US-NV");
       
+      long defaultTimeout = 60l * 60l; // 1 hour
+      properties.put(POLL_TIMEOUT, defaultTimeout);
+      properties.put(POLL_PERIOD, 2l);
+      properties.put(POLL_MAX_PERIOD, 2l * 10l);
+
+      properties.put(PROPERTY_SO_TIMEOUT, 60000 * 5);
+      properties.put(PROPERTY_CONNECTION_TIMEOUT, 60000 * 5);
+      
       return properties;
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/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
new file mode 100644
index 0000000..2fbadce
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/BaseProfitBricksRequestBinder.java
@@ -0,0 +1,73 @@
+/*
+ * 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.binder;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.MapBinder;
+
+import com.google.common.base.Strings;
+
+import org.jclouds.io.MutableContentMetadata;
+import org.jclouds.io.payloads.BaseMutableContentMetadata;
+
+public abstract class BaseProfitBricksRequestBinder<T> implements MapBinder {
+
+   protected final String paramName;
+
+   protected BaseProfitBricksRequestBinder(String paramName) {
+      this.paramName = checkNotNull(paramName, "Initialize 'paramName' in constructor");
+   }
+
+   @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));
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      throw new UnsupportedOperationException("Not supported yet.");
+   }
+
+   protected abstract String createPayload(T payload);
+
+   protected static String formatIfNotEmpty(String pattern, Object param) {
+      return Strings.isNullOrEmpty(nullableToString(param)) ? "" : String.format(pattern, param);
+   }
+
+   protected static String nullableToString(Object object) {
+      return object == null ? "" : object.toString();
+   }
+
+   protected <R extends HttpRequest> R createRequest(R fromRequest, String payload) {
+      MutableContentMetadata metadata = new BaseMutableContentMetadata();
+      metadata.setContentType("application/vnd.profitbricks.resource+json");
+      metadata.setContentLength(Long.valueOf(payload.getBytes().length));
+
+      fromRequest.setPayload(payload);
+      fromRequest.getPayload().setContentMetadata(metadata);
+      return fromRequest;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/AttachCdromRequestBinder.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/AttachCdromRequestBinder.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/AttachCdromRequestBinder.java
new file mode 100644
index 0000000..49faee2
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/AttachCdromRequestBinder.java
@@ -0,0 +1,61 @@
+/*
+ * 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.binder.server;
+
+import com.google.inject.Inject;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.jclouds.profitbricks.rest.binder.BaseProfitBricksRequestBinder;
+import org.apache.jclouds.profitbricks.rest.domain.Server;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class AttachCdromRequestBinder extends BaseProfitBricksRequestBinder<Server.Request.AttachCdromPayload> {
+
+   final Map<String, Object> requestBuilder;
+   final Json jsonBinder;
+
+   String dataCenterId;
+   String serverId;
+
+   @Inject
+   AttachCdromRequestBinder(Json jsonBinder) {
+      super("cdrom");
+      this.jsonBinder = jsonBinder;
+      this.requestBuilder = new HashMap<String, Object>();
+   }
+
+   @Override
+   protected String createPayload(Server.Request.AttachCdromPayload payload) {
+      
+      checkNotNull(payload, "payload");
+
+      dataCenterId = payload.dataCenterId();
+      serverId = payload.serverId();
+      
+      requestBuilder.put("id", payload.imageId());
+      return jsonBinder.toJson(requestBuilder);
+   }
+
+   @Override
+   protected <R extends HttpRequest> R createRequest(R fromRequest, String payload) {              
+      R request = (R) fromRequest.toBuilder().replacePath(String.format("/rest/datacenters/%s/servers/%s/cdroms", dataCenterId, serverId)).build();
+      return super.createRequest(request, payload);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/AttachVolumeRequestBinder.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/AttachVolumeRequestBinder.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/AttachVolumeRequestBinder.java
new file mode 100644
index 0000000..f843d34
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/AttachVolumeRequestBinder.java
@@ -0,0 +1,61 @@
+/*
+ * 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.binder.server;
+
+import com.google.inject.Inject;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.jclouds.profitbricks.rest.binder.BaseProfitBricksRequestBinder;
+import org.apache.jclouds.profitbricks.rest.domain.Server;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+public class AttachVolumeRequestBinder extends BaseProfitBricksRequestBinder<Server.Request.AttachVolumePayload> {
+
+   final Map<String, Object> requestBuilder;
+   final Json jsonBinder;
+
+   String dataCenterId;
+   String serverId;
+
+   @Inject
+   AttachVolumeRequestBinder(Json jsonBinder) {
+      super("volume");
+      this.jsonBinder = jsonBinder;
+      this.requestBuilder = new HashMap<String, Object>();
+   }
+
+   @Override
+   protected String createPayload(Server.Request.AttachVolumePayload payload) {
+      
+      checkNotNull(payload, "payload");
+
+      dataCenterId = payload.dataCenterId();
+      serverId = payload.serverId();
+      
+      requestBuilder.put("id", payload.imageId());
+      return jsonBinder.toJson(requestBuilder);
+   }
+
+   @Override
+   protected <R extends HttpRequest> R createRequest(R fromRequest, String payload) {              
+      R request = (R) fromRequest.toBuilder().replacePath(String.format("/rest/datacenters/%s/servers/%s/volumes", dataCenterId, serverId)).build();
+      return super.createRequest(request, payload);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/CreateServerRequestBinder.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/CreateServerRequestBinder.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/CreateServerRequestBinder.java
new file mode 100644
index 0000000..aaa07c1
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/CreateServerRequestBinder.java
@@ -0,0 +1,88 @@
+/*
+ * 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.binder.server;
+
+import com.google.inject.Inject;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.jclouds.profitbricks.rest.binder.BaseProfitBricksRequestBinder;
+import org.apache.jclouds.profitbricks.rest.domain.Server;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+
+public class CreateServerRequestBinder extends BaseProfitBricksRequestBinder<Server.Request.CreatePayload> {
+
+   final Map<String, Object> requestBuilder;
+   final Json jsonBinder;
+   String dataCenterId;
+
+   @Inject
+   CreateServerRequestBinder(Json jsonBinder) {
+      super("server");
+      this.jsonBinder = jsonBinder;
+      this.requestBuilder = new HashMap<String, Object>();
+   }
+
+   @Override
+   protected String createPayload(Server.Request.CreatePayload payload) {
+
+      dataCenterId = payload.dataCenterId();
+      
+      Map<String, Object> properties = new HashMap<String, Object>();
+      
+      properties.put("name",  payload.name());
+      properties.put("ram",   payload.ram());
+      properties.put("cores", payload.cores());
+      
+      if (payload.availabilityZone() != null)
+         properties.put("availabilityzone", payload.availabilityZone());
+      
+      if (payload.licenceType() != null)
+         properties.put("licencetype", payload.licenceType());
+      
+      if (payload.bootVolume() != null)
+         properties.put("bootVolume", payload.bootVolume());
+      else if (payload.bootCdrom() != null)
+         properties.put("bootCdrom", payload.bootCdrom());
+      
+      requestBuilder.put("properties", properties);
+      
+      Server.Entities entities = payload.entities();
+      
+      if (entities != null) {
+         
+         Map<String, Object> entitiesParams = new HashMap<String, Object>();
+         
+         if (entities.volumes() != null)
+            entitiesParams.put("volumes", entities.volumes());
+         
+         if (entities.nics() != null)
+            entitiesParams.put("nics", entities.nics());
+         
+         requestBuilder.put("entities", entitiesParams);
+      }
+
+      return jsonBinder.toJson(requestBuilder);
+   }
+
+   @Override
+   protected <R extends HttpRequest> R createRequest(R fromRequest, String payload) {              
+      R request = (R) fromRequest.toBuilder().replacePath(String.format("/rest/datacenters/%s/servers", dataCenterId)).build();
+      return super.createRequest(request, payload);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/UpdateServerRequestBinder.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/UpdateServerRequestBinder.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/UpdateServerRequestBinder.java
new file mode 100644
index 0000000..9d7eda9
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/binder/server/UpdateServerRequestBinder.java
@@ -0,0 +1,71 @@
+/*
+ * 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.binder.server;
+
+import com.google.inject.Inject;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.jclouds.profitbricks.rest.binder.BaseProfitBricksRequestBinder;
+import org.apache.jclouds.profitbricks.rest.domain.Server;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+
+public class UpdateServerRequestBinder extends BaseProfitBricksRequestBinder<Server.Request.UpdatePayload> {
+
+   final Map<String, Object> requestBuilder;
+   final Json jsonBinder;
+   String dataCenterId;
+   String serverId;
+
+   @Inject
+   UpdateServerRequestBinder(Json jsonBinder) {
+      super("server");
+      this.jsonBinder = jsonBinder;
+      this.requestBuilder = new HashMap<String, Object>();
+   }
+
+   @Override
+   protected String createPayload(Server.Request.UpdatePayload payload) {
+
+      dataCenterId = payload.dataCenterId();
+      serverId = payload.id();
+      
+      requestBuilder.put("name",  payload.name());
+      requestBuilder.put("ram",   payload.ram());
+      requestBuilder.put("cores", payload.cores());
+      
+      if (payload.availabilityZone() != null)
+         requestBuilder.put("availabilityzone", payload.availabilityZone());
+      
+      if (payload.licenceType() != null)
+         requestBuilder.put("licencetype", payload.licenceType());
+      
+      if (payload.bootVolume() != null)
+         requestBuilder.put("bootVolume", payload.bootVolume());
+      else if (payload.bootCdrom() != null)
+         requestBuilder.put("bootCdrom", payload.bootCdrom());
+      
+      return jsonBinder.toJson(requestBuilder);
+   }
+
+   @Override
+   protected <R extends HttpRequest> R createRequest(R fromRequest, String payload) {              
+      R request = (R) fromRequest.toBuilder().replacePath(String.format("/rest/datacenters/%s/servers/%s", dataCenterId, serverId)).build();
+      return super.createRequest(request, payload);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksComputeProperties.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksComputeProperties.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksComputeProperties.java
new file mode 100644
index 0000000..b05a8b8
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/config/ProfitBricksComputeProperties.java
@@ -0,0 +1,35 @@
+/*
+ * 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.config;
+
+public class ProfitBricksComputeProperties {
+
+   public static final String POLL_PREDICATE_DATACENTER = "jclouds.profitbricks.rest.predicate.datacenter";
+   public static final String POLL_PREDICATE_SNAPSHOT = "jclouds.profitbricks.rest.predicate.snapshot";
+
+   public static final String POLL_TIMEOUT = "jclouds.profitbricks.rest.poll.timeout";
+   public static final String POLL_PERIOD = "jclouds.profitbricks.rest.operation.poll.initial-period";
+   public static final String POLL_MAX_PERIOD = "jclouds.profitbricks.rest.operation.poll.max-period";
+   
+   public static final String TIMEOUT_NODE_RUNNING = "jclouds.profitbricks.rest.operation.poll.node.running";
+   public static final String TIMEOUT_NODE_SUSPENDED = "jclouds.profitbricks.rest.operation.poll.node.suspended";
+
+   private ProfitBricksComputeProperties() {
+      throw new AssertionError("Intentionally unimplemented");
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Firewall.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Firewall.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Firewall.java
new file mode 100644
index 0000000..6cc91a2
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Firewall.java
@@ -0,0 +1,135 @@
+/*
+ * 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.javax.annotation.Nullable;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Enums;
+import com.google.common.collect.ImmutableList;
+
+@AutoValue
+public abstract class Firewall {
+
+   public enum Protocol {
+
+      TCP, UDP, ICMP, ANY, UNRECOGNIZED;
+
+      public static Protocol fromValue(String value) {
+         return Enums.getIfPresent(Protocol.class, value).or(UNRECOGNIZED);
+      }
+   }
+
+   @Nullable
+   public abstract String id();
+
+   @Nullable
+   public abstract String nicId();
+
+   @Nullable
+   public abstract Boolean active();
+
+   @Nullable
+   public abstract ProvisioningState state();
+
+   @Nullable
+   public abstract List<Rule> rules();
+
+   public static Builder builder() {
+      return new AutoValue_Firewall.Builder()
+              .rules(ImmutableList.<Rule>of());
+   }
+
+   public abstract Builder toBuilder();
+
+   @AutoValue.Builder
+   public abstract static class Builder {
+
+      public abstract Builder id(String id);
+
+      public abstract Builder nicId(String nicId);
+
+      public abstract Builder active(Boolean active);
+
+      public abstract Builder state(ProvisioningState state);
+
+      public abstract Builder rules(List<Rule> rules);
+
+      abstract Firewall autoBuild();
+      
+      public Firewall build(){
+         Firewall built = autoBuild();
+         
+         return built.toBuilder()
+                 .rules(ImmutableList.copyOf(built.rules()))
+                 .autoBuild();
+      }
+   }
+
+   public static final class Request {
+
+      public static AddRulePayload createAddRulePayload(String nicId, List<Rule> rules) {
+         return new AutoValue_Firewall_Request_AddRulePayload(nicId, ImmutableList.copyOf(rules));
+      }
+
+      @AutoValue
+      public abstract static class AddRulePayload {
+
+         public abstract String nicId();
+
+         public abstract List<Rule> rules();
+
+      }
+   }
+
+   @AutoValue
+   public abstract static class Rule {
+
+      @Nullable
+      public abstract String id();
+
+      @Nullable
+      public abstract String name();
+
+      @Nullable
+      public abstract Integer portRangeEnd();
+
+      @Nullable
+      public abstract Integer portRangeStart();
+
+      @Nullable
+      public abstract Protocol protocol();
+
+      @Nullable
+      public abstract String sourceIp();
+
+      @Nullable
+      public abstract String sourceMac();
+
+      @Nullable
+      public abstract String targetIp();
+
+      @Nullable
+      public abstract Integer icmpCode();
+
+      @Nullable
+      public abstract Integer icmpType();
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/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
new file mode 100644
index 0000000..751ebc8
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Image.java
@@ -0,0 +1,110 @@
+/*
+ * 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 com.google.auto.value.AutoValue;
+import com.google.common.base.Enums;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+@AutoValue
+public abstract class Image {
+
+    public abstract String id();
+
+    public abstract String type();
+
+    public abstract String href();
+
+    @Nullable
+    public abstract Metadata metadata();
+
+    @Nullable
+    public abstract Properties properties();
+
+    @SerializedNames({"id", "type", "href", "metadata", "properties"})
+    public static Image create(String id, String type, String href, Metadata metadata, Properties properties) {
+        return new AutoValue_Image(id, type, href, metadata, properties);
+    }
+
+    @AutoValue
+    public abstract static class Properties {
+
+        public enum BusType {
+
+            IDE, SCSI, VIRTIO, UNRECOGNIZED;
+
+            public static BusType fromValue(String value) {
+                return Enums.getIfPresent(BusType.class, value).or(UNRECOGNIZED);
+            }
+        }
+
+        public abstract String name();
+
+        @Nullable
+        public abstract String description();
+        
+        public abstract Location location();
+
+        public abstract float size();
+        
+        public abstract boolean isPublic();
+        
+        public abstract LicenceType licenceType();
+
+        public abstract Image.Type imageType();
+
+        public abstract boolean cpuHotPlug();
+
+        public abstract boolean cpuHotUnplug();
+
+        public abstract boolean ramHotPlug();
+
+        public abstract boolean ramHotUnplug();
+
+        public abstract boolean nicHotPlug();
+
+        public abstract boolean nicHotUnplug();
+
+        public abstract boolean discVirtioHotPlug();
+
+        public abstract boolean discVirtioHotUnplug();
+
+        public abstract boolean discScsiHotPlug();
+
+        public abstract boolean discScsiHotUnplug();
+
+        @SerializedNames({"name", "description", "location", "size", "public", "licenceType", "imageType", "cpuHotPlug", "cpuHotUnplug", "ramHotPlug", "ramHotUnplug", "nicHotPlug", "nicHotUnplug", "discVirtioHotPlug", "discVirtioHotUnplug", "discScsiHotPlug", "discScsiHotUnplug"})
+        public static Image.Properties create(String name, String description, Location location, float size, boolean isPublic, LicenceType licenceType, Image.Type imageType,
+                boolean cpuHotPlug, boolean cpuHotUnplug, boolean ramHotPlug, boolean ramHotUnplug, boolean nicHotPlug, boolean nicHotUnplug, boolean discVirtioHotPlug,
+                boolean discVirtioHotUnplug, boolean discScsiHotPlug, boolean discScsiHotUnplug) {
+
+            return new AutoValue_Image_Properties(name, description, location, size, isPublic, licenceType, imageType, cpuHotPlug, cpuHotUnplug, ramHotPlug, ramHotUnplug, nicHotPlug, nicHotUnplug, discVirtioHotPlug, discVirtioHotUnplug, discScsiHotPlug, discScsiHotUnplug);
+
+        }
+    }
+    
+   public enum Type {
+
+      HDD, CDROM, UNRECOGNIZED;
+
+      public static Type fromValue(String v) {
+         return Enums.getIfPresent(Type.class, v).or(UNRECOGNIZED);
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Images.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Images.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Images.java
new file mode 100644
index 0000000..c01dd82
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Images.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+import static com.google.common.collect.ImmutableList.copyOf;
+
+@AutoValue
+public abstract class Images {
+
+   public abstract String id();
+
+   public abstract String type();
+
+   public abstract String href();
+
+   @Nullable
+   public abstract List<Image> items();
+
+   @SerializedNames({"id", "type", "href", "items"})
+   public static Images create(String id, String type, String href, List<Image> items) {
+      return new AutoValue_Images(id, type, href, items == null ? ImmutableList.<Image>of() : copyOf(items));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/LicenceType.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/LicenceType.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/LicenceType.java
index 6a6bcb7..8b2a999 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/LicenceType.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/LicenceType.java
@@ -23,9 +23,6 @@ public enum LicenceType {
    WINDOWS, LINUX, OTHER, UNRECOGNIZED;
 
    public static LicenceType fromValue(String v) {
-      return Enums
-              .getIfPresent(LicenceType.class, v)
-              .or(UNRECOGNIZED);
+      return Enums.getIfPresent(LicenceType.class, v).or(UNRECOGNIZED);
    }
-
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Location.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Location.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Location.java
index 44c6e58..48536ca 100644
--- a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Location.java
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/Location.java
@@ -19,23 +19,33 @@ package org.apache.jclouds.profitbricks.rest.domain;
 import com.google.common.base.Enums;
 
 public enum Location {
-
-   DE_FKB("de/fkb"),
-   DE_FRA("de/fra"),
-   US_LAS("us/las"),
-   US_LAS_DEV("us/lasdev"),
-   UNRECOGNIZED("unknown");
+   
+   DE_FKB("de/fkb", "Germany, Karlsruhe"),
+   DE_FRA("de/fra", "Germany, Frankfurt (M)"),
+   US_LAS("us/las", "USA, Las Vegas"),
+   US_LASDEV("us/lasdev", "USA Developer cluster"),
+   UNRECOGNIZED("unrecognized", "Unrecognized location");
 
    private final String id;
+   private final String description;
 
-   Location(String id) {
+   Location(String id, String description) {
       this.id = id;
+      this.description = description;
    }
-
+   
    public String value() {
       return id;
    }
 
+   public String getId() {
+      return id;
+   }
+
+   public String getDescription() {
+      return description;
+   }
+
    public static Location fromValue(String v) {
       return Enums
               .getIfPresent(Location.class, v)

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/ProvisioningState.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/ProvisioningState.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/ProvisioningState.java
new file mode 100644
index 0000000..81634fa
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/domain/ProvisioningState.java
@@ -0,0 +1,28 @@
+/*
+ * 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 com.google.common.base.Enums;
+
+public enum ProvisioningState {
+
+   INACTIVE, INPROCESS, AVAILABLE, DELETED, ERROR, UNRECOGNIZED;
+
+   public static ProvisioningState fromValue(String value) {
+      return Enums.getIfPresent(ProvisioningState.class, value).or(UNRECOGNIZED);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/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 0616426..d832ea0 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
@@ -17,18 +17,23 @@
 package org.apache.jclouds.profitbricks.rest.domain;
 
 import com.google.auto.value.AutoValue;
+import com.google.common.base.Enums;
+import static org.apache.jclouds.profitbricks.rest.util.Preconditions.checkCores;
 import org.jclouds.javax.annotation.Nullable;
 import org.jclouds.json.SerializedNames;
 
 @AutoValue
 public abstract class Server {
-
+   
    public abstract String id();
+   
+   @Nullable
+   public abstract String dataCenterId();
 
    public abstract String type();
 
    public abstract String href();
-
+   
    @Nullable
    public abstract Metadata metadata();
 
@@ -38,9 +43,9 @@ public abstract class Server {
    @Nullable
    public abstract Entities entities();
 
-   @SerializedNames({"id", "type", "href", "metadata", "properties", "entities"})
-   public static Server create(String id, String type, String href, Metadata metadata, Properties properties, Entities entities) {
-      return new AutoValue_Server(id, type, href, metadata, properties, entities);
+   @SerializedNames({"id", "dataCenterId", "type", "href", "metadata", "properties", "entities"})
+   public static Server create(String id, String dataCenterId, String type, String href, Metadata metadata, Properties properties, Entities entities) {
+      return new AutoValue_Server(id, dataCenterId, type, href, metadata, properties, entities);
    }
 
    @AutoValue
@@ -52,9 +57,14 @@ public abstract class Server {
 
       public abstract int ram();
 
+      @Nullable
       public abstract AvailabilityZone availabilityZone();
-
-      public abstract VMState vmState();
+      
+      @Nullable
+      public abstract Server.Status vmState();
+      
+      @Nullable
+      public abstract LicenceType licenceType();
 
       @Nullable
       public abstract Volume bootVolume();
@@ -62,9 +72,9 @@ public abstract class Server {
       @Nullable
       public abstract Volume bootCdrom();
 
-      @SerializedNames({"name", "cores", "ram", "availabilityZone", "vmState", "bootVolume", "bootCdrom"})
-      public static Properties create(String name, int cores, int ram, AvailabilityZone availabilityZone, VMState vmState, Volume bootVolume, Volume bootCdrom) {
-         return new AutoValue_Server_Properties(name, cores, ram, availabilityZone, vmState, bootVolume, bootCdrom);
+      @SerializedNames({"name", "cores", "ram", "availabilityZone", "vmState", "licenceType", "bootVolume", "bootCdrom"})
+      public static Properties create(String name, int cores, int ram, AvailabilityZone availabilityZone, Server.Status vmState, LicenceType licenceType, Volume bootVolume, Volume bootCdrom) {
+         return new AutoValue_Server_Properties(name, cores, ram, availabilityZone, vmState, licenceType, bootVolume, bootCdrom);
       }
 
    }
@@ -72,16 +82,214 @@ public abstract class Server {
    @AutoValue
    public abstract static class Entities {
 
-      public abstract Volumes cdroms();
-
+      @Nullable
+      public abstract Images cdroms();
+      
+      @Nullable
       public abstract Volumes volumes();
 
+      @Nullable
       public abstract Nics nics();
 
       @SerializedNames({"cdroms", "volumes", "nics"})
-      public static Entities create(Volumes cdroms, Volumes volumes, Nics nics) {
-	 return new AutoValue_Server_Entities(cdroms, volumes, nics);
+      public static Entities create(Images cdroms, Volumes volumes, Nics nics) {
+         return new AutoValue_Server_Entities(cdroms, volumes, nics);
       }
 
    }
+   
+   public static final class Request {
+
+      public static CreatePayload.Builder creatingBuilder() {
+         return new AutoValue_Server_Request_CreatePayload.Builder();
+      }
+
+      public static UpdatePayload.Builder updatingBuilder() {
+         return new AutoValue_Server_Request_UpdatePayload.Builder();
+      }
+      
+      public static AttachCdromPayload.Builder attachCdromBuilder() {
+         return new AutoValue_Server_Request_AttachCdromPayload.Builder();
+      }
+      
+      public static AttachVolumePayload.Builder attachVolumeBuilder() {
+         return new AutoValue_Server_Request_AttachVolumePayload.Builder();
+      }
+
+      @AutoValue
+      public abstract static class CreatePayload {
+
+         public abstract String name();
+         
+         public abstract int cores();
+
+         public abstract int ram();
+
+         public abstract String dataCenterId();
+
+         @Nullable
+         public abstract Volume bootVolume();
+
+         @Nullable
+         public abstract Volume bootCdrom();
+
+         @Nullable
+         public abstract AvailabilityZone availabilityZone();
+         
+         @Nullable
+         public abstract LicenceType licenceType();
+        
+         @Nullable
+         public abstract Entities entities();
+                  
+         @AutoValue.Builder
+         public abstract static class Builder {
+
+            public abstract Builder name(String name);
+
+            public abstract Builder cores(int cores);
+
+            public abstract Builder ram(int ram);
+
+            public abstract Builder dataCenterId(String dataCenterId);
+
+            public abstract Builder bootVolume(Volume bootVolume);
+
+            public abstract Builder bootCdrom(Volume bootCdrom);
+
+            public abstract Builder availabilityZone(AvailabilityZone availabilityZone);
+            
+            public abstract Builder licenceType(LicenceType licenceType);
+           
+            public abstract Builder entities(Entities entities);
+            
+            abstract CreatePayload autoBuild();
+
+            public CreatePayload build() {
+               CreatePayload payload = autoBuild();
+               checkCores(payload.cores());
+               return payload;
+            }
+         }
+
+      }
+
+      @AutoValue
+      public abstract static class UpdatePayload {
+
+         public abstract String id();
+         
+         public abstract String dataCenterId();
+
+         @Nullable
+         public abstract String name();
+         
+         @Nullable
+         public abstract Integer cores();
+
+         @Nullable
+         public abstract Integer ram();
+
+         @Nullable
+         public abstract Volume bootVolume();
+
+         @Nullable
+         public abstract Volume bootCdrom();
+
+         @Nullable
+         public abstract AvailabilityZone availabilityZone();
+         
+         @Nullable
+         public abstract LicenceType licenceType();
+
+         @AutoValue.Builder
+         public abstract static class Builder {
+
+            public abstract Builder id(String id);
+            
+            public abstract Builder dataCenterId(String dataCenterId);
+            
+            public abstract Builder name(String name);
+
+            public abstract Builder cores(Integer cores);
+
+            public abstract Builder ram(Integer ram);
+
+            public abstract Builder bootVolume(Volume bootVolume);
+
+            public abstract Builder bootCdrom(Volume bootCdrom);
+
+            public abstract Builder availabilityZone(AvailabilityZone availabilityZone);
+            
+            public abstract Builder licenceType(LicenceType licenceType);
+
+            abstract UpdatePayload autoBuild();
+
+            public UpdatePayload build() {
+               UpdatePayload payload = autoBuild();
+               if (payload.cores() != null)
+                  checkCores(payload.cores());
+               return payload;
+            }
+         }
+      }
+      
+      @AutoValue
+      public abstract static class AttachCdromPayload {
+
+         public abstract String imageId();
+         public abstract String dataCenterId();
+         public abstract String serverId();
+         
+         @AutoValue.Builder
+         public abstract static class Builder {
+            
+            public abstract Builder imageId(String imageId);
+            public abstract Builder dataCenterId(String dataCenterId);
+            public abstract Builder serverId(String serverId);
+
+            abstract AttachCdromPayload autoBuild();
+
+            public AttachCdromPayload build() {
+               return autoBuild();
+            }
+         }
+      }
+      
+      @AutoValue 
+      public abstract static class AttachVolumePayload {
+
+         public abstract String imageId();
+         public abstract String dataCenterId();
+         public abstract String serverId();
+         
+         @AutoValue.Builder
+         public abstract static class Builder {
+            
+            public abstract Builder imageId(String imageId);
+            public abstract Builder dataCenterId(String dataCenterId);
+            public abstract Builder serverId(String serverId);
+
+            abstract AttachVolumePayload autoBuild();
+
+            public AttachVolumePayload build() {
+               return autoBuild();
+            }
+         }
+      }
+   }
+   
+   public enum Status {
+
+      NOSTATE, RUNNING, BLOCKED, PAUSED, SHUTDOWN, SHUTOFF, CRASHED, UNRECOGNIZED;
+
+      public String value() {
+         return name();
+      }
+
+      public static Status fromValue(String v) {
+         return Enums.getIfPresent(Status.class, v).or(UNRECOGNIZED);
+      }
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/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 29d91d0..b978294 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
@@ -57,14 +57,14 @@ public abstract class Volume {
 
         public abstract String type();
 
-        public abstract int size();
+        public abstract float size();
 
         @Nullable
         public abstract String image();
 
         @Nullable
         public abstract String imagePassword();
-
+        
         public abstract BusType bus();
 
         public abstract LicenceType licenceType();
@@ -89,10 +89,11 @@ public abstract class Volume {
 
         public abstract boolean discScsiHotUnplug();
 
-        public abstract int deviceNumber();
+        @Nullable
+        public abstract Integer deviceNumber();
 
         @SerializedNames({"name", "type", "size", "image", "imagePassword", "bus", "licenceType", "cpuHotPlug", "cpuHotUnplug", "ramHotPlug", "ramHotUnplug", "nicHotPlug", "nicHotUnplug", "discVirtioHotPlug", "discVirtioHotUnplug", "discScsiHotPlug", "discScsiHotUnplug", "deviceNumber"})
-        public static Volume.Properties create(String name, String type, int size, String image, String imagePassword, BusType bus, LicenceType licenceType,
+        public static Volume.Properties create(String name, String type, float size, String image, String imagePassword, BusType bus, LicenceType licenceType,
                 boolean cpuHotPlug, boolean cpuHotUnplug, boolean ramHotPlug, boolean ramHotUnplug, boolean nicHotPlug, boolean nicHotUnplug, boolean discVirtioHotPlug,
                 boolean discVirtioHotUnplug, boolean discScsiHotPlug, boolean discScsiHotUnplug, int deviceNumber) {
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/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 bef6f52..5df496d 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
@@ -109,7 +109,6 @@ public interface DataCenterApi extends Closeable {
    @Named("datacenter:delete")
    @DELETE
    @Path("/{id}")
-   @ResponseParser(DataCenterParser.class)
    @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
    void delete(@PathParam("id") String id);
    

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/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
new file mode 100644
index 0000000..51b3996
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ImageApi.java
@@ -0,0 +1,39 @@
+/*
+ * 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.features;
+
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+import java.io.Closeable;
+import javax.ws.rs.Path;
+import org.apache.jclouds.profitbricks.rest.domain.Image;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.rest.annotations.RequestFilters;
+
+@Path("/images")
+@RequestFilters(BasicAuthentication.class)
+public interface ImageApi extends Closeable {
+   
+   static final class ImageParser extends ParseJson<Image> {
+      @Inject ImageParser(Json json) {
+         super(json, TypeLiteral.get(Image.class));
+      }
+   }
+   
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/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
new file mode 100644
index 0000000..fa1718c
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/ServerApi.java
@@ -0,0 +1,194 @@
+/*
+ * 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.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.util.List;
+import javax.inject.Named;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+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;
+import org.apache.jclouds.profitbricks.rest.binder.server.UpdateServerRequestBinder;
+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.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;
+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.util.Strings2;
+
+@Path("/datacenters/{dataCenterId}/servers")
+@RequestFilters(BasicAuthentication.class)
+public interface ServerApi extends Closeable {
+   
+   @Named("server:list")
+   @GET
+   @SelectJson("items")
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<Server> getList(@PathParam("dataCenterId") String dataCenterId);
+
+   @Named("server:list")
+   @GET
+   @SelectJson("items")
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<Server> getList(@PathParam("dataCenterId") String dataCenterId, DepthOptions options);
+   
+   @Named("server:get")
+   @GET   
+   @Path("/{serverId}")
+   @ResponseParser(ServerApi.ServerParser.class)
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   Server getServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+
+   @Named("server:get")
+   @GET   
+   @Path("/{serverId}")
+   @ResponseParser(ServerApi.ServerParser.class)
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   Server getServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, DepthOptions options);
+   
+   @Named("server:create")
+   @POST
+   @MapBinder(CreateServerRequestBinder.class)
+   @ResponseParser(ServerApi.ServerParser.class)
+   Server createServer(@PayloadParam("server") Server.Request.CreatePayload payload);
+   
+   @Named("server:update")
+   @PATCH
+   @Path("/{serverId}")
+   @MapBinder(UpdateServerRequestBinder.class)
+   @ResponseParser(ServerApi.ServerParser.class)
+   @Produces("application/vnd.profitbricks.partial-properties+json")
+   Server updateServer(@PayloadParam("server") Server.Request.UpdatePayload payload);
+   
+   @Named("server:delete")
+   @DELETE
+   @Path("/{serverId}")
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void deleteServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+   
+   @Named("server:volume:list")
+   @GET
+   @Path("/{serverId}/volumes")
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   @SelectJson("items")
+   List<Volume> listAttachedVolumes(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+   
+   @Named("server:volume:attach")
+   @POST
+   @MapBinder(AttachVolumeRequestBinder.class)
+   @ResponseParser(VolumeApi.VolumeParser.class)
+   Volume attachVolume(@PayloadParam("volume") Server.Request.AttachVolumePayload payload);
+   
+   @Named("server:volume:delete")
+   @DELETE
+   @Path("/{serverId}/volumes/{volumeId}")
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void detachVolume(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("volumeId") String volumeId);
+   
+   @Named("server:volume:get")
+   @GET
+   @Path("/{serverId}/volumes/{volumeId}")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @ResponseParser(VolumeApi.VolumeParser.class)
+   Volume getVolume(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("volumeId") String volumeId);
+   
+   @Named("server:cdrom:list")
+   @GET
+   @Path("/{serverId}/cdroms")
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   @SelectJson("items")
+   List<Image> listAttachedCdroms(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+   
+   @Named("server:cdrom:attach")
+   @POST
+   @MapBinder(AttachCdromRequestBinder.class)
+   @ResponseParser(ImageApi.ImageParser.class)
+   Image attachCdrom(@PayloadParam("cdrom") Server.Request.AttachCdromPayload payload);
+   
+   @Named("server:cdrom:delete")
+   @DELETE
+   @Path("/{serverId}/cdroms/{cdRomId}")
+   @Fallback(Fallbacks.VoidOnNotFoundOr404.class)
+   void detachCdrom(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("cdRomId") String cdRomId);
+   
+   @Named("server:cdrom:get")
+   @GET
+   @Path("/{serverId}/cdroms/{cdRomId}")
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   @ResponseParser(ImageApi.ImageParser.class)
+   Image getCdrom(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId, @PathParam("cdRomId") String cdRomId);
+   
+   @Named("server:reboot")
+   @POST
+   @Path("/{serverId}/reboot")
+   void 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);
+   
+   @Named("server:stop")
+   @POST
+   @Path("/{serverId}/stop")
+   void stopServer(@PathParam("dataCenterId") String dataCenterId, @PathParam("serverId") String serverId);
+   
+   static final class ServerParser extends ParseJson<Server> {
+      
+      final ParseId parseService;
+      
+      @Inject ServerParser(Json json, ParseId parseId) {
+         super(json, TypeLiteral.get(Server.class));
+         this.parseService = parseId;
+      }
+
+      @Override
+      public <V> V apply(InputStream stream, Type type) throws IOException {
+         try {
+            return (V) json.fromJson(this.parseService.parseId(Strings2.toStringAndClose(stream), "datacenters", "dataCenterId"), type
+            );
+         } finally {
+            if (stream != null)
+               stream.close();
+         }
+      }
+   }
+   
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/VolumeApi.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/VolumeApi.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/VolumeApi.java
new file mode 100644
index 0000000..028a648
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/features/VolumeApi.java
@@ -0,0 +1,39 @@
+/*
+ * 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.features;
+
+import com.google.inject.Inject;
+import com.google.inject.TypeLiteral;
+import java.io.Closeable;
+import javax.ws.rs.Path;
+import org.apache.jclouds.profitbricks.rest.domain.Volume;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.rest.annotations.RequestFilters;
+
+@Path("/volumes")
+@RequestFilters(BasicAuthentication.class)
+public interface VolumeApi extends Closeable {
+   
+   static final class VolumeParser extends ParseJson<Volume> {
+      @Inject VolumeParser(Json json) {
+         super(json, TypeLiteral.get(Volume.class));
+      }
+   }
+   
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ids/ServerRef.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ids/ServerRef.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ids/ServerRef.java
new file mode 100644
index 0000000..b2d4177
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/ids/ServerRef.java
@@ -0,0 +1,31 @@
+/*
+ * 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.ids;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class ServerRef {
+   
+   public abstract String dataCenterId();
+   public abstract String serverId();
+      
+   public static ServerRef create(String dataCenterId, String serverId) {
+      return new AutoValue_ServerRef(dataCenterId, serverId);
+   }
+    
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/ApiPredicatesModule.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/ApiPredicatesModule.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/ApiPredicatesModule.java
new file mode 100644
index 0000000..6dc7e0f
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/ApiPredicatesModule.java
@@ -0,0 +1,140 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import com.google.common.base.Predicate;
+import com.google.inject.Inject;
+import com.google.inject.Provides;
+import org.apache.jclouds.profitbricks.rest.ProfitBricksApi;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PERIOD;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_TIMEOUT;
+import org.apache.jclouds.profitbricks.rest.domain.ProvisioningState;
+import org.apache.jclouds.profitbricks.rest.domain.Server;
+import com.google.inject.AbstractModule;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.POLL_MAX_PERIOD;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.TIMEOUT_NODE_RUNNING;
+import static org.apache.jclouds.profitbricks.rest.config.ProfitBricksComputeProperties.TIMEOUT_NODE_SUSPENDED;
+import org.apache.jclouds.profitbricks.rest.ids.ServerRef;
+import static org.jclouds.util.Predicates2.retry;
+
+public class ApiPredicatesModule extends AbstractModule {
+
+   @Override
+   protected void configure() {}
+
+   @Provides
+   @Singleton
+   @Named(POLL_PREDICATE_DATACENTER)
+   Predicate<String> provideDataCenterAvailablePredicate(final ProfitBricksApi api, ComputeConstants constants) {
+      return retry(new DataCenterProvisioningStatePredicate(
+              api, ProvisioningState.AVAILABLE),
+              constants.pollTimeout(), constants.pollPeriod(), constants.pollMaxPeriod(), TimeUnit.SECONDS);
+   }
+
+   @Provides
+   @Named(TIMEOUT_NODE_RUNNING)
+   Predicate<ServerRef> provideServerRunningPredicate(final ProfitBricksApi api, ComputeConstants constants) {
+      return retry(new ServerStatusPredicate(
+              api, Server.Status.RUNNING),
+              constants.pollTimeout(), constants.pollPeriod(), constants.pollMaxPeriod(), TimeUnit.SECONDS);
+   }
+   
+   @Provides
+   @Named(TIMEOUT_NODE_SUSPENDED)
+   Predicate<ServerRef> provideServerSuspendedPredicate(final ProfitBricksApi api, ComputeConstants constants) {
+      return retry(new ServerStatusPredicate(
+              api, Server.Status.SHUTOFF),
+              constants.pollTimeout(), constants.pollPeriod(), constants.pollMaxPeriod(), TimeUnit.SECONDS);
+   }
+   
+   static class DataCenterProvisioningStatePredicate implements Predicate<String> {
+
+      private final ProfitBricksApi api;
+      private final ProvisioningState expectedState;
+
+      public DataCenterProvisioningStatePredicate(ProfitBricksApi api, ProvisioningState expectedState) {
+         this.api = checkNotNull(api, "api must not be null");
+         this.expectedState = checkNotNull(expectedState, "expectedState must not be null");
+      }
+
+      @Override
+      public boolean apply(String input) {
+         checkNotNull(input, "datacenter id");
+         return api.dataCenterApi().getDataCenter(input).metadata().state().toString().equals(expectedState.toString());
+      }
+
+   }
+
+   static class ServerStatusPredicate implements Predicate<ServerRef> {
+
+      private final ProfitBricksApi api;
+      private final Server.Status expectedStatus;
+
+      public ServerStatusPredicate(ProfitBricksApi api, Server.Status expectedStatus) {
+         this.api = checkNotNull(api, "api must not be null");
+         this.expectedStatus = checkNotNull(expectedStatus, "expectedStatus must not be null");
+      }
+
+      @Override
+      public boolean apply(ServerRef serverRef) {
+         checkNotNull(serverRef, "serverRef");
+         
+         Server server = api.serverApi().getServer(serverRef.dataCenterId(), serverRef.serverId());
+         
+         if (server == null || server.properties().vmState() == null)
+            return false;
+         
+         return server.properties().vmState() == expectedStatus;
+      }
+
+   }
+
+   @Singleton
+   public static class ComputeConstants {
+
+      @Inject
+      @Named(POLL_TIMEOUT)
+      private String pollTimeout;
+
+      @Inject
+      @Named(POLL_PERIOD)
+      private String pollPeriod;
+
+      @Inject
+      @Named(POLL_MAX_PERIOD)
+      private String pollMaxPeriod;
+
+      public long pollTimeout() {
+         return Long.parseLong(pollTimeout);
+      }
+
+      public long pollPeriod() {
+         return Long.parseLong(pollPeriod);
+      }
+
+      public long pollMaxPeriod() {
+         return Long.parseLong(pollMaxPeriod);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/ParseId.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/ParseId.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/ParseId.java
new file mode 100644
index 0000000..594e105
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/ParseId.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jclouds.profitbricks.rest.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.reflect.TypeToken;
+import com.google.inject.Inject;
+import java.lang.reflect.Type;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.jclouds.json.Json;
+
+public class ParseId {
+   
+   final Json jsonBinder;
+   
+   @Inject
+   ParseId(Json jsonBinder) {
+      this.jsonBinder = checkNotNull(jsonBinder, "jsonBinder");
+   }
+   
+   public String parseId (String json, String prefix, String key) {
+         
+      Type mapType = new TypeToken<Map<String, Object>>(){}.getType();
+      Map<String, String> jsonMap = jsonBinder.fromJson(json, mapType);
+
+      Pattern p = Pattern.compile(String.format(".*%s\\/([a-z|\\-|\\d]*).*", prefix));
+      Matcher m = p.matcher(jsonMap.get("href"));
+
+      if (m.matches()) {
+         String dataCenterId = m.group(1);
+         jsonMap = new ImmutableMap.Builder<String, String>()
+                 .putAll(jsonMap)
+                 .put(key, dataCenterId)
+                 .build();
+         json = jsonBinder.toJson(jsonMap);
+      }
+
+      return json;
+   }
+   
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/Preconditions.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/Preconditions.java b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/Preconditions.java
new file mode 100644
index 0000000..9b2e97b
--- /dev/null
+++ b/profitbricks-rest/src/main/java/org/apache/jclouds/profitbricks/rest/util/Preconditions.java
@@ -0,0 +1,90 @@
+/*
+ * 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.util;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static com.google.common.net.InetAddresses.isInetAddress;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.jclouds.profitbricks.rest.domain.Firewall;
+import org.apache.jclouds.profitbricks.rest.domain.Firewall.Protocol;
+
+/**
+ * Static convenience methods for validating various ProfitBricks domain preconditions
+ */
+public final class Preconditions {
+
+   private static final Pattern INVALID_CHARS = Pattern.compile("^.*[@/\\|'`’^].*$");
+
+   public static void checkInvalidChars(String name) {
+      checkArgument(!isNullOrEmpty(name), "Name is required.");
+      checkArgument(!INVALID_CHARS.matcher(name).matches(), "Name must not contain any of: @ / \\ | ' ` ’ ^");
+   }
+
+   public static void checkIp(String ip) {
+      checkArgument(isInetAddress(ip), "IP '%s' is invalid", ip);
+   }
+
+   public static void checkIps(List<String> ips) {
+      checkNotNull(ips, "Null ip list");
+      for (String ip : ips)
+         checkIp(ip);
+   }
+
+   public static void checkPortRange(Integer portRangeStart, Integer portRangeEnd, Firewall.Protocol protocol) {
+      checkArgument(!(portRangeEnd == null ^ portRangeStart == null), "Port range must be both present or null");
+      if (portRangeEnd != null) {
+         checkArgument(protocol == Firewall.Protocol.TCP || protocol == Firewall.Protocol.UDP, "Port range can only be set for TCP or UDP");
+         checkArgument(portRangeEnd > portRangeStart, "portRangeEnd must be greater than portRangeStart");
+         checkArgument(portRangeEnd >= 1 && portRangeEnd <= 65534, "Port range end must be 1 to 65534");
+         checkArgument(portRangeStart >= 1 && portRangeStart <= 65534, "Port range start must be 1 to 65534");
+      }
+   }
+
+   public static void checkIcmp(Integer icmpType, Integer icmpCode, Protocol protocol) {
+      checkNotNull(protocol, "Protocol can't be null");
+      if (protocol == Protocol.ICMP) {
+         if (icmpType != null)
+            checkArgument(icmpType >= 1 && icmpType <= 254, "ICMP type must be 1 to 254");
+         if (icmpCode != null)
+            checkArgument(icmpCode >= 1 && icmpCode <= 254, "ICMP code must be 1 to 254");
+      }
+   }
+
+   public static void checkLanId(Integer id) {
+      checkArgument(id >= 0, "LAN ID must be non-negative");
+   }
+
+   public static void checkCores(Integer cores) {
+      checkArgument(cores > 0, "Number of cores must be atleast 1.");
+   }
+
+   public static void checkRam(Integer ram, Boolean isRamHotPlug) {
+      int minRam = (isRamHotPlug == null || !isRamHotPlug) ? 256 : 1024;
+      checkArgument(ram >= minRam && ram % 256 == 0, "RAM must be multiples of 256 with minimum of 256 MB "
+              + "(1024 MB if ramHotPlug is enabled)");
+   }
+
+   public static void checkSize(Float size) {
+      checkArgument(size > 1, "Storage size must be > 1GB");
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiLiveTest.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiLiveTest.java b/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiLiveTest.java
index c2a1e44..83922ec 100644
--- a/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiLiveTest.java
+++ b/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiLiveTest.java
@@ -18,12 +18,11 @@ package org.apache.jclouds.profitbricks.rest.features;
 
 import java.util.List;
 import org.apache.jclouds.profitbricks.rest.domain.DataCenter;
-import org.apache.jclouds.profitbricks.rest.domain.Location;
 import org.apache.jclouds.profitbricks.rest.domain.options.DepthOptions;
 import org.apache.jclouds.profitbricks.rest.internal.BaseProfitBricksLiveTest;
+import org.testng.annotations.Test;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
-import org.testng.annotations.Test;
 
 @Test(groups = "live", testName = "DataCenterApiLiveTest")
 public class DataCenterApiLiveTest extends BaseProfitBricksLiveTest {
@@ -98,11 +97,7 @@ public class DataCenterApiLiveTest extends BaseProfitBricksLiveTest {
       
       deleteDataCenter(dataCenter.id());
    }
-   
-   private DataCenter createDataCenter() {
-      return dataCenterApi().create("test-data-center", "example description", Location.US_LAS.value());
-   }
-   
+      
    private DataCenter getDataCenter(String id) {
       return dataCenterApi().getDataCenter(id);
    }
@@ -110,11 +105,7 @@ public class DataCenterApiLiveTest extends BaseProfitBricksLiveTest {
    private DataCenter getDataCenter(String id, DepthOptions options) {
       return dataCenterApi().getDataCenter(id, options);
    }
-   
-   private void deleteDataCenter(String id) {
-      dataCenterApi().delete(id);
-   }
-   
+      
    private DataCenterApi dataCenterApi() {
       return api.dataCenterApi();
    }

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/cfb4311f/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiMockTest.java
----------------------------------------------------------------------
diff --git a/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiMockTest.java b/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiMockTest.java
index 7c8fa1a..022eb92 100644
--- a/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiMockTest.java
+++ b/profitbricks-rest/src/test/java/org/apache/jclouds/profitbricks/rest/features/DataCenterApiMockTest.java
@@ -115,15 +115,14 @@ public class DataCenterApiMockTest extends BaseProfitBricksApiMockTest {
    
    @Test
    public void testDelete() throws InterruptedException {
-      server.enqueue(
-         new MockResponse().setBody("")
-      );
+      server.enqueue(response204());
       
       dataCenterApi().delete("some-id");
       assertEquals(server.getRequestCount(), 1);
       assertSent(server, "DELETE", "/datacenters/some-id");
    }
    
+   @Test
    public void testDeleteWith404() throws InterruptedException {
       server.enqueue(response404());