JCLOUDS-702: JCloud ProfitBricks provider implementation

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

Branch: refs/heads/master
Commit: cb45048a680b9788bf3ef1ef6964da5533d4eabe
Parents: 
Author: Reijhanniel Jearl Campos <[email protected]>
Authored: Sat Jan 10 11:08:09 2015 +0800
Committer: Ignasi Barrera <[email protected]>
Committed: Mon Jan 12 10:00:19 2015 +0100

----------------------------------------------------------------------
 providers/profitbricks/pom.xml                  | 147 +++++++++++
 .../jclouds/profitbricks/ProfitBricksApi.java   |  28 ++
 .../profitbricks/ProfitBricksApiMetadata.java   |  82 ++++++
 .../ProfitBricksProviderMetadata.java           |  66 +++++
 .../binder/BaseProfitBricksRequestBinder.java   |  75 ++++++
 .../CreateDataCenterRequestBinder.java          |  44 ++++
 .../UpdateDataCenterRequestBinder.java          |  44 ++++
 .../internal/ProvisioningStatusAware.java       |  27 ++
 .../ProvisioningStatusPollingPredicate.java     |  56 ++++
 .../config/ProfitBricksHttpApiModule.java       |  70 +++++
 .../jclouds/profitbricks/domain/DataCenter.java | 137 ++++++++++
 .../jclouds/profitbricks/domain/Location.java   |  50 ++++
 .../profitbricks/domain/ProvisioningState.java  |  30 +++
 .../profitbricks/domain/ServiceFault.java       |  95 +++++++
 .../profitbricks/features/DataCenterApi.java    | 134 ++++++++++
 .../handlers/ProfitBricksHttpErrorHandler.java  |  70 +++++
 ...usFromPayloadHttpCommandExecutorService.java | 122 +++++++++
 .../ProfitBricksSoapMessageEnvelope.java        |  59 +++++
 .../parser/BaseProfitBricksResponseHandler.java |  69 +++++
 .../parser/ServiceFaultResponseHandler.java     |  63 +++++
 .../BaseDataCenterResponseHandler.java          |  43 ++++
 .../DataCenterInfoResponseHandler.java          |  62 +++++
 .../DataCenterListResponseHandler.java          |  65 +++++
 .../GetProvisioningStateResponseHandler.java    |  52 ++++
 .../profitbricks/BaseProfitBricksLiveTest.java  |  45 ++++
 .../ProfitBricksProviderMetadataTest.java       |  29 +++
 .../CreateDataCenterRequestBinderTest.java      |  47 ++++
 .../UpdateDataCenterRequestBinderTest.java      |  46 ++++
 .../ProvisioningStatusPollingPredicateTest.java |  74 ++++++
 .../features/DataCenterApiLiveTest.java         | 127 +++++++++
 .../features/DataCenterApiMockTest.java         | 255 +++++++++++++++++++
 ...omPayloadHttpCommandExecutorServiceTest.java |  98 +++++++
 .../ProfitBricksSoapMessageEnvelopeTest.java    |  57 +++++
 .../http/parser/BaseResponseHandlerTest.java    |  61 +++++
 .../parser/ServiceFaultResponseHandlerTest.java |  49 ++++
 .../DataCenterInfoResponseHandlerTest.java      |  54 ++++
 .../DataCenterListResponseHandlerTest.java      |  53 ++++
 ...GetProvisioningStateResponseHandlerTest.java | 110 ++++++++
 .../internal/BaseProfitBricksMockTest.java      |  88 +++++++
 .../resources/datacenter/datacenter-cleared.xml |  12 +
 .../resources/datacenter/datacenter-created.xml |  13 +
 .../resources/datacenter/datacenter-deleted.xml |  10 +
 .../datacenter/datacenter-state-inprocess.xml   |   8 +
 .../resources/datacenter/datacenter-state.xml   |   8 +
 .../resources/datacenter/datacenter-updated.xml |  12 +
 .../test/resources/datacenter/datacenter.xml    |  80 ++++++
 .../test/resources/datacenter/datacenters.xml   |  19 ++
 .../src/test/resources/fault-400.xml            |  17 ++
 .../src/test/resources/fault-401.html           |  43 ++++
 .../src/test/resources/fault-404.xml            |  17 ++
 50 files changed, 3122 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/pom.xml
----------------------------------------------------------------------
diff --git a/providers/profitbricks/pom.xml b/providers/profitbricks/pom.xml
new file mode 100644
index 0000000..ab0003d
--- /dev/null
+++ b/providers/profitbricks/pom.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.jclouds.labs</groupId>
+        <artifactId>jclouds-labs</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+    </parent>
+  
+    <!-- TODO: when out of labs, switch to org.jclouds.api -->
+    <artifactId>profitbricks</artifactId>
+    <name>jclouds ProfitBricks api</name>
+    <description>jclouds components to access an implementation of 
ProfitBricks</description>
+    <packaging>bundle</packaging>
+
+    <properties>
+        
<test.profitbricks.endpoint>https://api.profitbricks.com/1.3</test.profitbricks.endpoint>
+        <test.profitbricks.identity>FIXME</test.profitbricks.identity>
+        <test.profitbricks.credential>FIXME</test.profitbricks.credential>
+        <test.profitbricks.api-version>1.3</test.profitbricks.api-version>
+        <test.profitbricks.template />
+        
<jclouds.osgi.export>org.jclouds.profitbricks*;version="${project.version}"</jclouds.osgi.export>
+        <jclouds.osgi.import>
+            org.jclouds.labs*;version="${project.version}",
+            org.jclouds*;version="${jclouds.version}",
+            *
+        </jclouds.osgi.import>
+    </properties>
+  
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <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.value</groupId>
+            <artifactId>auto-value</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.apache.jclouds</groupId>
+            <artifactId>jclouds-core</artifactId>
+            <version>${jclouds.version}</version>
+            <type>test-jar</type>
+            <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>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp</groupId>
+            <artifactId>mockwebserver</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <!-- Already provided by jclouds-sshj -->
+                <exclusion>
+                    <groupId>org.bouncycastle</groupId>
+                    <artifactId>bcprov-jdk15on</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jclouds.driver</groupId>
+            <artifactId>jclouds-slf4j</artifactId>
+            <version>${jclouds.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+  
+    <profiles>
+        <profile>
+            <id>live</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>integration</id>
+                                <phase>integration-test</phase>
+                                <goals>
+                                    <goal>test</goal>
+                                </goals>
+                                <configuration>
+                                    <threadCount>1</threadCount>
+                                    <systemPropertyVariables>
+                                        
<test.profitbricks.endpoint>${test.profitbricks.endpoint}</test.profitbricks.endpoint>
+                                        
<test.profitbricks.identity>${test.profitbricks.identity}</test.profitbricks.identity>
+                                        
<test.profitbricks.credential>${test.profitbricks.credential}</test.profitbricks.credential>
+                                        
<test.profitbricks.api-version>${test.profitbricks.api-version}</test.profitbricks.api-version>
+                                        
<test.profitbricks.template>${test.profitbricks.template}</test.profitbricks.template>
+                                    </systemPropertyVariables>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksApi.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksApi.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksApi.java
new file mode 100644
index 0000000..d1cb1e1
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksApi.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.jclouds.profitbricks;
+
+import java.io.Closeable;
+
+import org.jclouds.profitbricks.features.DataCenterApi;
+import org.jclouds.rest.annotations.Delegate;
+
+public interface ProfitBricksApi extends Closeable {
+
+   @Delegate
+   DataCenterApi dataCenterApi();
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksApiMetadata.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksApiMetadata.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksApiMetadata.java
new file mode 100644
index 0000000..f51dc5b
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksApiMetadata.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks;
+
+import java.net.URI;
+import java.util.Properties;
+
+import org.jclouds.profitbricks.config.ProfitBricksHttpApiModule;
+import org.jclouds.apis.ApiMetadata;
+import 
org.jclouds.profitbricks.config.ProfitBricksHttpApiModule.ProfitBricksHttpCommandExecutorServiceModule;
+import org.jclouds.rest.internal.BaseHttpApiMetadata;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Implementation of {@link ApiMetadata} for ProfitBricks API.
+ */
+public class ProfitBricksApiMetadata extends 
BaseHttpApiMetadata<ProfitBricksApi> {
+
+   public ProfitBricksApiMetadata() {
+      this(new Builder());
+   }
+
+   @Override
+   public Builder toBuilder() {
+      return new Builder().fromApiMetadata(this);
+   }
+
+   protected ProfitBricksApiMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public static Properties defaultProperties() {
+      Properties properties = BaseHttpApiMetadata.defaultProperties();
+      return properties;
+   }
+
+   public static class Builder extends 
BaseHttpApiMetadata.Builder<ProfitBricksApi, Builder> {
+
+      protected Builder() {
+        id("profitbricks")
+                .name("ProfitBricks API")
+                .identityName("API Username")
+                .credentialName("API Password")
+                
.documentation(URI.create("https://www.profitbricks.com/sites/default/files/profitbricks_api_1_3.pdf";))
+                .defaultEndpoint("https://api.profitbricks.com/1.3";)
+                .version("1.3")
+                // .view(ComputeServiceContext.class)
+                .defaultProperties(ProfitBricksApiMetadata.defaultProperties())
+                .defaultModules(ImmutableSet.<Class<? extends Module>>of(
+                                ProfitBricksHttpApiModule.class,
+                                
ProfitBricksHttpCommandExecutorServiceModule.class
+                        ));
+      }
+
+      @Override
+      public ProfitBricksApiMetadata build() {
+        return new ProfitBricksApiMetadata(this);
+      }
+
+      @Override
+      protected Builder self() {
+        return this;
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksProviderMetadata.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksProviderMetadata.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksProviderMetadata.java
new file mode 100644
index 0000000..d66ed15
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/ProfitBricksProviderMetadata.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks;
+
+import com.google.auto.service.AutoService;
+import java.net.URI;
+import org.jclouds.providers.ProviderMetadata;
+import org.jclouds.providers.internal.BaseProviderMetadata;
+
+@AutoService(ProviderMetadata.class)
+public class ProfitBricksProviderMetadata extends BaseProviderMetadata {
+
+   public ProfitBricksProviderMetadata(Builder builder) {
+      super(builder);
+   }
+
+   public ProfitBricksProviderMetadata() {
+      super(builder());
+   }
+
+   @Override
+   public Builder toBuilder() {
+      return builder().fromProviderMetadata(this);
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static class Builder extends BaseProviderMetadata.Builder {
+
+      protected Builder() {
+        id("profitbricks")
+                .name("ProfitBricks Cloud Compute 2.0")
+                .homepage(URI.create("http://www.profitbricks.com";))
+                
.console(URI.create("https://my.profitbricks.com/dashboard/dcdr2/";))
+                .linkedServices("profitbricks")
+                .apiMetadata(new ProfitBricksApiMetadata());
+      }
+
+      @Override
+      public ProfitBricksProviderMetadata build() {
+        return new ProfitBricksProviderMetadata(this);
+      }
+
+      @Override
+      public Builder fromProviderMetadata(ProviderMetadata in) {
+        super.fromProviderMetadata(in);
+        return this;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/BaseProfitBricksRequestBinder.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/BaseProfitBricksRequestBinder.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/BaseProfitBricksRequestBinder.java
new file mode 100644
index 0000000..af85c5e
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/BaseProfitBricksRequestBinder.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.binder;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+
+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 String formatIfNotEmpty(String pattern, Object param) {
+      return Strings.isNullOrEmpty(param.toString()) ? "" : 
String.format(pattern, param);
+   }
+
+   protected 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(MediaType.TEXT_XML);
+      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/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/datacenter/CreateDataCenterRequestBinder.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/datacenter/CreateDataCenterRequestBinder.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/datacenter/CreateDataCenterRequestBinder.java
new file mode 100644
index 0000000..8696c0e
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/datacenter/CreateDataCenterRequestBinder.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.binder.datacenter;
+
+import static java.lang.String.format;
+
+import org.jclouds.profitbricks.binder.BaseProfitBricksRequestBinder;
+import org.jclouds.profitbricks.domain.DataCenter;
+
+public class CreateDataCenterRequestBinder extends 
BaseProfitBricksRequestBinder<DataCenter.Request.CreatePayload> {
+
+   protected final StringBuilder requestBuilder;
+
+   CreateDataCenterRequestBinder() {
+      super("dataCenter");
+      this.requestBuilder = new StringBuilder(128);
+   }
+
+   @Override
+   protected String createPayload(DataCenter.Request.CreatePayload payload) {
+      requestBuilder.append("<ws:createDataCenter>")
+             .append("<request>")
+             .append(format("<dataCenterName>%s</dataCenterName>", 
payload.name()))
+             .append(format("<location>%s</location>", 
payload.location().value()))
+             .append("</request>")
+             .append("</ws:createDataCenter>");
+      return requestBuilder.toString();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/datacenter/UpdateDataCenterRequestBinder.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/datacenter/UpdateDataCenterRequestBinder.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/datacenter/UpdateDataCenterRequestBinder.java
new file mode 100644
index 0000000..920e9bf
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/binder/datacenter/UpdateDataCenterRequestBinder.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.binder.datacenter;
+
+import static java.lang.String.format;
+
+import org.jclouds.profitbricks.binder.BaseProfitBricksRequestBinder;
+import org.jclouds.profitbricks.domain.DataCenter;
+
+public class UpdateDataCenterRequestBinder extends 
BaseProfitBricksRequestBinder<DataCenter.Request.UpdatePayload> {
+
+   protected final StringBuilder requestBuilder;
+
+   UpdateDataCenterRequestBinder() {
+      super("dataCenter");
+      this.requestBuilder = new StringBuilder(128);
+   }
+
+   @Override
+   protected String createPayload(DataCenter.Request.UpdatePayload payload) {
+      requestBuilder.append("<ws:updateDataCenter>")
+              .append("<request>")
+              .append(format("<dataCenterId>%s</dataCenterId>", payload.id()))
+              .append(format("<dataCenterName>%s</dataCenterName>", 
payload.name()))
+              .append("</request>")
+              .append("</ws:updateDataCenter>");
+      return requestBuilder.toString();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/compute/internal/ProvisioningStatusAware.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/compute/internal/ProvisioningStatusAware.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/compute/internal/ProvisioningStatusAware.java
new file mode 100644
index 0000000..84f7128
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/compute/internal/ProvisioningStatusAware.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.compute.internal;
+
+/**
+ * An enumeration of ProfitBricks domain classes containing a property 
'ProvisioningState'.
+ *
+ * @see ProvisioningStatusPollingPredicate
+ */
+public enum ProvisioningStatusAware {
+
+   DATACENTER;
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/compute/internal/ProvisioningStatusPollingPredicate.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/compute/internal/ProvisioningStatusPollingPredicate.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/compute/internal/ProvisioningStatusPollingPredicate.java
new file mode 100644
index 0000000..d8a7521
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/compute/internal/ProvisioningStatusPollingPredicate.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.compute.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.profitbricks.ProfitBricksApi;
+import org.jclouds.profitbricks.domain.ProvisioningState;
+
+import com.google.common.base.Predicate;
+
+/**
+ * A custom predicate for waiting until a virtual resource satisfies the given 
expected status
+ * <p>
+ * Performing api requests on a datacenter that is not {@link 
ProvisioningState#AVAILABLE} is not allowed. On some
+ * cases, the API user gets blocked from further requests, and will then need 
to contact tech support for api lock
+ * release.
+ */
+public class ProvisioningStatusPollingPredicate implements Predicate<String> {
+
+   private final ProfitBricksApi api;
+   private final ProvisioningStatusAware domain;
+   private final ProvisioningState expect;
+
+   public ProvisioningStatusPollingPredicate(ProfitBricksApi api, 
ProvisioningStatusAware domain, ProvisioningState expect) {
+      this.api = checkNotNull(api, "API null");
+      this.expect = checkNotNull(expect, "Expected state null");
+      this.domain = checkNotNull(domain, "Domain null");
+   }
+
+   @Override
+   public boolean apply(String input) {
+      checkNotNull(input, "Virtual item id can't be null.");
+      switch (domain) {
+         case DATACENTER:
+            return expect == api.dataCenterApi().getDataCenterState(input);
+         default:
+            throw new IllegalArgumentException("Unknown domain '" + domain + 
"'");
+      }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/config/ProfitBricksHttpApiModule.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/config/ProfitBricksHttpApiModule.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/config/ProfitBricksHttpApiModule.java
new file mode 100644
index 0000000..57728be
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/config/ProfitBricksHttpApiModule.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.config;
+
+import org.jclouds.http.HttpCommandExecutorService;
+import org.jclouds.profitbricks.ProfitBricksApi;
+import org.jclouds.profitbricks.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.http.config.ConfiguresHttpCommandExecutorService;
+import org.jclouds.http.config.SSLModule;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.profitbricks.domain.ServiceFault;
+import 
org.jclouds.profitbricks.http.ResponseStatusFromPayloadHttpCommandExecutorService;
+import org.jclouds.profitbricks.http.parser.ServiceFaultResponseHandler;
+import org.jclouds.rest.ConfiguresHttpApi;
+import org.jclouds.rest.config.HttpApiModule;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Injector;
+import com.google.inject.Provides;
+import com.google.inject.Scopes;
+
+/**
+ * Configures the ProfitBricks connection.
+ */
+@ConfiguresHttpApi
+public class ProfitBricksHttpApiModule extends HttpApiModule<ProfitBricksApi> {
+
+   @Override
+   protected void bindErrorHandlers() {
+      
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ProfitBricksHttpErrorHandler.class);
+      
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ProfitBricksHttpErrorHandler.class);
+      
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ProfitBricksHttpErrorHandler.class);
+   }
+
+   @ConfiguresHttpCommandExecutorService
+   public static class ProfitBricksHttpCommandExecutorServiceModule extends 
AbstractModule {
+
+      @Override
+      protected void configure() {
+        install(new SSLModule());
+        
bind(HttpCommandExecutorService.class).to(ResponseStatusFromPayloadHttpCommandExecutorService.class)
+                .in(Scopes.SINGLETON);
+      }
+
+      @Provides
+      public ParseSax<ServiceFault> serviceFaultParser(ParseSax.Factory 
factory, Injector injector) {
+        return 
factory.create(injector.getInstance(ServiceFaultResponseHandler.class));
+      }
+
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/DataCenter.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/DataCenter.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/DataCenter.java
new file mode 100644
index 0000000..d5f9893
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/DataCenter.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.domain;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+import java.util.regex.Pattern;
+
+import org.jclouds.javax.annotation.Nullable;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class DataCenter {
+
+   public abstract String id();
+
+   @Nullable public abstract String name();
+
+   public abstract int version();
+
+   @Nullable public abstract ProvisioningState state();
+
+   @Nullable public abstract Location location();
+
+//   @Nullable public abstract List<Server> servers();
+//   @Nullable public abstract List<Storage> storages();
+//   @Nullable public abstract List<LoadBalancer> loadBalancers();
+   public static DataCenter create(String id, String name, int version, 
ProvisioningState state, Location location) {
+      return new AutoValue_DataCenter(id, name, version, state, location);
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder().fromDataCenter(this);
+   }
+
+   public static final class Builder {
+
+      private String id;
+      private String name;
+      private ProvisioningState state;
+      private Location location;
+      private int version;
+//      private List<Server> servers;
+//      private List<Storage> storage;
+//      private List<LoadBalancer> loadBalancer;
+
+      public Builder id(String id) {
+        this.id = id;
+        return this;
+      }
+
+      public Builder name(String name) {
+        this.name = name;
+        return this;
+      }
+
+      public Builder state(ProvisioningState state) {
+        this.state = state;
+        return this;
+      }
+
+      public Builder location(Location location) {
+        this.location = location;
+        return this;
+      }
+
+      public Builder version(int version) {
+        this.version = version;
+        return this;
+      }
+
+      public DataCenter build() {
+        return DataCenter.create(id, name, version, state, location);
+      }
+
+      public Builder fromDataCenter(DataCenter in) {
+        return 
this.id(in.id()).name(in.name()).version(in.version()).state(in.state()).location(in.location());
+      }
+   }
+
+   public static final class Request {
+      
+      @AutoValue
+      public abstract static class CreatePayload {
+
+        public abstract String name();
+
+        public abstract Location location();
+
+        public static CreatePayload create(String name, Location location) {
+            checkInvalidChars(name);
+           return new AutoValue_DataCenter_Request_CreatePayload(name, 
location);
+        }
+
+      }
+
+      @AutoValue
+      public abstract static class UpdatePayload {
+
+        public abstract String id();
+
+        public abstract String name();
+
+        public static UpdatePayload create(String id, String name) {
+            checkInvalidChars(name);
+           return new AutoValue_DataCenter_Request_UpdatePayload(id, name);
+        }
+      }
+      
+      private static final Pattern INVALID_CHARS = 
Pattern.compile("^.*[@/\\|'`’^].*$");
+      
+      private static void checkInvalidChars(String name){
+         checkArgument(!isNullOrEmpty(name), "Name is required.");
+         checkArgument(!INVALID_CHARS.matcher(name).matches(), "Name must not 
contain any of: @ / \\ | ' ` ’ ^");
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/Location.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/Location.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/Location.java
new file mode 100644
index 0000000..969629a
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/Location.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.domain;
+
+public enum Location {
+
+   DE_FKB("de/fkb"),
+   DE_FRA("de/fra"),
+   US_LAS("us/las"),
+   UNRECOGNIZED("unknown");
+
+   private final String id;
+
+   Location(String id) {
+      this.id = id;
+   }
+
+   public String value() {
+      return id;
+   }
+
+   public static Location fromValue(String v) {
+      try {
+        return valueOf(v);
+      } catch (IllegalArgumentException ex) {
+        return UNRECOGNIZED;
+      }
+   }
+
+   public static Location fromId(String id) {
+      for (Location location : values())
+        if (location.id.equals(id))
+           return location;
+      return UNRECOGNIZED;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/ProvisioningState.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/ProvisioningState.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/ProvisioningState.java
new file mode 100644
index 0000000..2a9e0b6
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/ProvisioningState.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.domain;
+
+public enum ProvisioningState {
+
+   INACTIVE, INPROCESS, AVAILABLE, DELETED, ERROR, UNRECOGNIZED;
+
+   public static ProvisioningState fromValue(String value) {
+      try {
+        return valueOf(value);
+      } catch (IllegalArgumentException e) {
+        return UNRECOGNIZED;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/ServiceFault.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/ServiceFault.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/ServiceFault.java
new file mode 100644
index 0000000..0e1303e
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/domain/ServiceFault.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.domain;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class ServiceFault {
+
+   public enum FaultCode {
+
+      BAD_REQUEST,
+      UNEXPECTED,
+      UNAUTHORIZED,
+      RESOURCE_NOT_FOUND,
+      RESOURCE_DELETED,
+      PROVISIONING_IN_PROCESS,
+      PROVISIONING_NO_CHANGES,
+      OVER_LIMIT_SETTING,
+      SERVER_EXCEED_CAPACITY,
+      SERVICE_UNAVAILABLE,
+      UNRECOGNIZED;
+
+      public static FaultCode fromValue(String v) {
+        try {
+           return valueOf(v);
+        } catch (IllegalArgumentException ex) {
+           return UNRECOGNIZED;
+        }
+      }
+   }
+
+   public abstract FaultCode faultCode();
+
+   public abstract int httpCode();
+
+   public abstract String message();
+
+   public abstract int requestId();
+
+   public static ServiceFault create(FaultCode faultCode, int httpCode, String 
message, int requestId) {
+      return new AutoValue_ServiceFault(faultCode, httpCode, message, 
requestId);
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public static final class Builder {
+
+      private FaultCode faultCode;
+      private int httpCode;
+      private String message;
+      private int requestId;
+
+      public Builder faultCode(FaultCode code) {
+        this.faultCode = code;
+        return this;
+      }
+
+      public Builder httpCode(int httpCode) {
+        this.httpCode = httpCode;
+        return this;
+      }
+
+      public Builder message(String message) {
+        this.message = message;
+        return this;
+      }
+
+      public Builder requestId(int requestId) {
+        this.requestId = requestId;
+        return this;
+      }
+
+      public ServiceFault build() {
+        return create(faultCode, httpCode, message, requestId);
+      }
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/features/DataCenterApi.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/features/DataCenterApi.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/features/DataCenterApi.java
new file mode 100644
index 0000000..f660730
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/features/DataCenterApi.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.features;
+
+import java.util.List;
+import javax.inject.Named;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.Fallbacks;
+import org.jclouds.http.filters.BasicAuthentication;
+import 
org.jclouds.profitbricks.binder.datacenter.CreateDataCenterRequestBinder;
+import 
org.jclouds.profitbricks.binder.datacenter.UpdateDataCenterRequestBinder;
+import org.jclouds.profitbricks.domain.DataCenter;
+import org.jclouds.profitbricks.domain.ProvisioningState;
+import org.jclouds.profitbricks.http.filters.ProfitBricksSoapMessageEnvelope;
+import 
org.jclouds.profitbricks.http.parser.datacenter.DataCenterInfoResponseHandler;
+import 
org.jclouds.profitbricks.http.parser.datacenter.DataCenterListResponseHandler;
+import 
org.jclouds.profitbricks.http.parser.state.GetProvisioningStateResponseHandler;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.XMLResponseParser;
+
+@RequestFilters({BasicAuthentication.class, 
ProfitBricksSoapMessageEnvelope.class})
+@Consumes(MediaType.TEXT_XML)
+@Produces(MediaType.TEXT_XML)
+public interface DataCenterApi {
+
+   /**
+    * @return Returns a list of all Virtual Data Centers created by the user, 
including ID, name and version number.
+    */
+   @POST
+   @Named("datacenter:getall")
+   @Payload("<ws:getAllDataCenters/>")
+   @XMLResponseParser(DataCenterListResponseHandler.class)
+   @Fallback(Fallbacks.EmptyListOnNotFoundOr404.class)
+   List<DataCenter> getAllDataCenters();
+
+   /**
+    * @param identifier Data Center identifier
+    * @return Returns information about an existing virtual data center's 
state and configuration or <code>null</code>
+    * if it doesn't exist.
+    */
+   @POST
+   @Named("datacenter:get")
+   
@Payload("<ws:getDataCenter><dataCenterId>{id}</dataCenterId></ws:getDataCenter>")
+   @XMLResponseParser(DataCenterInfoResponseHandler.class)
+   @Fallback(Fallbacks.NullOnNotFoundOr404.class)
+   DataCenter getDataCenter(@PayloadParam("id") String identifier);
+
+   /**
+    * This is a lightweight function for polling the current provisioning 
state of the Virtual Data Center. It is
+    * recommended to use this function for large Virtual Data Centers to query 
request results.
+    * <p>
+    * @param identifier Data Center identifier
+    */
+   @POST
+   @Named("datacenter:getstate")
+   
@Payload("<ws:getDataCenterState><dataCenterId>{id}</dataCenterId></ws:getDataCenterState>")
+   @XMLResponseParser(GetProvisioningStateResponseHandler.class)
+   ProvisioningState getDataCenterState(@PayloadParam("id") String identifier);
+
+   /**
+    * Creates and saves a new, empty Virtual Data Center. Returns its 
identifier for further reference.
+    * <p>
+    * <b>Note: </b>Data center names cannot start with or contain (@, /, \, |, 
‘’, ‘)
+    * <p>
+    * @param createRequest VDC payload containing dataCenterName, region
+    * @return Response containing requestId, dataCenterId, version, and 
location
+    */
+   @POST
+   @Named("datacenter:create")
+   @MapBinder(CreateDataCenterRequestBinder.class)
+   @XMLResponseParser(DataCenterInfoResponseHandler.class)
+   DataCenter createDataCenter(@PayloadParam("dataCenter") 
DataCenter.Request.CreatePayload createRequest);
+
+   /**
+    * Updates the information associated to an existing Virtual Data Center.
+    * <p>
+    * @param updateRequest VDC payload containing dataCenterId, and name
+    * @return Response containing requestId, dataCenterId, version
+    */
+   @POST
+   @Named("datacenter:update")
+   @MapBinder(UpdateDataCenterRequestBinder.class)
+   @XMLResponseParser(DataCenterInfoResponseHandler.class)
+   DataCenter updateDataCenter(@PayloadParam("dataCenter") 
DataCenter.Request.UpdatePayload updateRequest);
+
+   /**
+    * Removes all components from an existing Virtual Data Center.
+    * <p>
+    * @param identifier Identifier of the virtual data center
+    * @return Response containing requestId, dataCenterId, version
+    */
+   @POST
+   @Named("datacenter:clear")
+   
@Payload("<ws:clearDataCenter><dataCenterId>{id}</dataCenterId></ws:clearDataCenter>")
+   @XMLResponseParser(DataCenterInfoResponseHandler.class)
+   DataCenter clearDataCenter(@PayloadParam("id") String identifier);
+
+   /**
+    * Deletes an Virtual Data Center. If a previous request on the target data 
center is still in progress, the data
+    * center is going to be deleted after this request has been completed. 
Once a Data Center has been deleted, no
+    * further request can be performed on it.
+    * <p>
+    * @param identifier Identifier of the virtual data center
+    * @return Returns a boolean indicating whether delete operation was made
+    */
+   @POST
+   @Named("datacenter:delete")
+   
@Payload("<ws:deleteDataCenter><dataCenterId>{id}</dataCenterId></ws:deleteDataCenter>")
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean deleteDataCenter(@PayloadParam("id") String identifier);
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/handlers/ProfitBricksHttpErrorHandler.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/handlers/ProfitBricksHttpErrorHandler.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/handlers/ProfitBricksHttpErrorHandler.java
new file mode 100644
index 0000000..6453327
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/handlers/ProfitBricksHttpErrorHandler.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.handlers;
+
+import static org.jclouds.util.Closeables2.closeQuietly;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.InsufficientResourcesException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+/**
+ * Parse ProfitBricks API errors and set the appropriate exception.
+ *
+ * @see 
org.jclouds.profitbricks.http.ResponseStatusFromPayloadHttpCommandExecutorService
+ *
+ */
+@Singleton
+public class ProfitBricksHttpErrorHandler implements HttpErrorHandler {
+
+   @Override
+   public void handleError(final HttpCommand command, final HttpResponse 
response) {
+      Exception exception = null;
+      try {
+        switch (response.getStatusCode()) {
+           case 400:
+           case 405:
+              exception = new IllegalArgumentException(response.getMessage(), 
exception);
+              break;
+           case 401:
+              exception = new AuthorizationException(response.getMessage(), 
exception);
+              break;
+           case 402:
+           case 409:
+              exception = new IllegalStateException(response.getMessage(), 
exception);
+              break;
+           case 404:
+           case 410:
+              if (!command.getCurrentRequest().getMethod().equals("DELETE"))
+                 exception = new 
ResourceNotFoundException(response.getMessage(), exception);
+              break;
+           case 413:
+           case 503:
+              exception = new 
InsufficientResourcesException(response.getMessage(), exception);
+              break;
+        }
+      } finally {
+        closeQuietly(response.getPayload());
+        command.setException(exception);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/ResponseStatusFromPayloadHttpCommandExecutorService.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/ResponseStatusFromPayloadHttpCommandExecutorService.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/ResponseStatusFromPayloadHttpCommandExecutorService.java
new file mode 100644
index 0000000..78b0c8b
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/ResponseStatusFromPayloadHttpCommandExecutorService.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.http;
+
+import static org.jclouds.util.Closeables2.closeQuietly;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.Proxy;
+import java.net.URI;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpUtils;
+import org.jclouds.http.IOExceptionRetryHandler;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.http.handlers.DelegatingErrorHandler;
+import org.jclouds.http.handlers.DelegatingRetryHandler;
+import org.jclouds.http.internal.HttpWire;
+import org.jclouds.http.internal.JavaUrlHttpCommandExecutorService;
+import org.jclouds.io.ContentMetadataCodec;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+import org.jclouds.profitbricks.domain.ServiceFault;
+
+import com.google.common.base.Function;
+import com.google.common.base.Supplier;
+import com.google.common.io.ByteStreams;
+import com.google.inject.Inject;
+
+/**
+ * Custom implementation of the HTTP driver to read actual http status and 
message from SOAP Fault.
+ * <br/>
+ * ProfitBricks API errors are always returned with 500 HTTP code. This class 
parses and reads the SOAP response to map the actual http code
+ * and message
+ */
+@Singleton
+public class ResponseStatusFromPayloadHttpCommandExecutorService extends 
JavaUrlHttpCommandExecutorService {
+
+   private final ParseSax<ServiceFault> faultHandler;
+
+   @Inject
+   ResponseStatusFromPayloadHttpCommandExecutorService(HttpUtils utils, 
ContentMetadataCodec contentMetadataCodec,
+           DelegatingRetryHandler retryHandler, IOExceptionRetryHandler 
ioRetryHandler,
+           DelegatingErrorHandler errorHandler, HttpWire wire, 
@Named("untrusted") HostnameVerifier verifier,
+           @Named("untrusted") Supplier<SSLContext> 
untrustedSSLContextProvider, Function<URI, Proxy> proxyForURI,
+           ParseSax<ServiceFault> faultHandler) {
+      super(utils, contentMetadataCodec, retryHandler, ioRetryHandler, 
errorHandler, wire, verifier, untrustedSSLContextProvider, proxyForURI);
+      this.faultHandler = faultHandler;
+   }
+
+   @Override
+   protected HttpResponse invoke(HttpURLConnection connection) throws 
IOException, InterruptedException {
+      HttpResponse originalResponse = super.invoke(connection);
+      HttpResponse.Builder<?> responseBuilder = originalResponse.toBuilder();
+
+      if (hasPayload(originalResponse) && hasServerError(originalResponse)) {
+         // As we need to read the response body to determine if there are 
errors, but we may need to process the body
+         // again later in the response parsers if everything is OK, we buffer 
the body into an InputStream we can reset
+         InputStream in = null;
+         InputStream originalInputStream = 
originalResponse.getPayload().openStream();
+         if (originalInputStream instanceof ByteArrayInputStream)
+            in = originalInputStream;
+         else
+            try {
+               in = new 
ByteArrayInputStream(ByteStreams.toByteArray(originalInputStream));
+            } finally {
+               closeQuietly(originalInputStream);
+            }
+
+         try {
+            ServiceFault fault = faultHandler.parse(in);
+            if (fault != null)
+               responseBuilder
+                       .statusCode(fault.httpCode())
+                       .message(fault.message());
+         } catch (Exception ex) {
+            // ignore
+         } finally {
+            // Reset the input stream and set the payload, so it can be read 
again
+            // by the response and error parsers
+            if (in != null) {
+               in.reset();
+               Payload payload = Payloads.newInputStreamPayload(in);
+               contentMetadataCodec.fromHeaders(payload.getContentMetadata(), 
originalResponse.getHeaders());
+               responseBuilder.payload(payload);
+            }
+         }
+      }
+
+      return responseBuilder.build();
+   }
+
+   private static boolean hasServerError(final HttpResponse response) {
+      return response.getStatusCode() >= 500;
+   }
+
+   private static boolean hasPayload(final HttpResponse response) {
+      return response.getPayload() != null && 
response.getPayload().getRawContent() != null;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/filters/ProfitBricksSoapMessageEnvelope.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/filters/ProfitBricksSoapMessageEnvelope.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/filters/ProfitBricksSoapMessageEnvelope.java
new file mode 100644
index 0000000..fce8e21
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/filters/ProfitBricksSoapMessageEnvelope.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.http.filters;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.jclouds.http.HttpException;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpRequestFilter;
+import org.jclouds.http.HttpUtils;
+import org.jclouds.io.ContentMetadata;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+
+/**
+ * Filters {@link HttpRequest} request and wraps request body into SOAP 
envelope.
+ */
+public class ProfitBricksSoapMessageEnvelope implements HttpRequestFilter {
+
+   private final String SOAP_PREFIX
+          = "<soapenv:Envelope 
xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"; 
xmlns:ws=\"http://ws.api.profitbricks.com/\";>"
+          + "<soapenv:Header/>"
+          + "<soapenv:Body>";
+
+   private final String SOAP_SUFFIX = "</soapenv:Body></soapenv:Envelope>";
+
+   @Override
+   public HttpRequest filter(HttpRequest request) throws HttpException {
+      checkNotNull(request.getPayload(), "HTTP Request must contain payload 
message.");
+      return createSoapRequest(request);
+   }
+
+   private HttpRequest createSoapRequest(HttpRequest request) {
+      Payload oldPayload = request.getPayload();
+      ContentMetadata oldMetadata = oldPayload.getContentMetadata();
+
+      String body = 
SOAP_PREFIX.concat(oldPayload.getRawContent().toString()).concat(SOAP_SUFFIX);
+      Payload newPayload = Payloads.newStringPayload(body);
+      HttpUtils.copy(oldMetadata, newPayload.getContentMetadata());
+      
newPayload.getContentMetadata().setContentLength(Long.valueOf(body.length())); 
// resize, add prefix/suffix length
+
+      return request.toBuilder().payload(newPayload).build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/BaseProfitBricksResponseHandler.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/BaseProfitBricksResponseHandler.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/BaseProfitBricksResponseHandler.java
new file mode 100644
index 0000000..9e66159
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/BaseProfitBricksResponseHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.http.parser;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Date;
+
+import org.jclouds.date.DateCodec;
+import org.jclouds.date.DateCodecFactory;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.SAXException;
+
+public abstract class BaseProfitBricksResponseHandler<T> extends 
ParseSax.HandlerForGeneratedRequestWithResult<T> {
+
+   protected final DateCodec dateCodec;
+
+   private final StringBuilder strBuilder;
+
+   public BaseProfitBricksResponseHandler(DateCodecFactory dateCodec) {
+      this.dateCodec = checkNotNull(checkNotNull(dateCodec, "dateCodecFactory 
null").iso8601(), "iso8601 date codec null");
+      this.strBuilder = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      strBuilder.append(ch, start, length);
+   }
+
+   protected final Date textToIso8601Date() {
+      return dateCodec.toDate(textToStringValue());
+   }
+
+   protected String textToStringValue() {
+      return strBuilder.toString().trim();
+   }
+
+   protected int textToIntValue() {
+      return Integer.parseInt(textToStringValue());
+   }
+
+   protected boolean textToBooleanValue() {
+      return Boolean.parseBoolean(textToStringValue());
+   }
+
+   protected void clearTextBuffer() {
+      strBuilder.setLength(0);
+   }
+
+   @Override
+   public abstract void endElement(String uri, String localName, String qName) 
throws SAXException;
+
+   protected abstract void setPropertyOnEndTag(String qName);
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/ServiceFaultResponseHandler.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/ServiceFaultResponseHandler.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/ServiceFaultResponseHandler.java
new file mode 100644
index 0000000..c6a504b
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/ServiceFaultResponseHandler.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.http.parser;
+
+import org.jclouds.date.DateCodecFactory;
+import org.jclouds.profitbricks.domain.ServiceFault;
+import org.xml.sax.SAXException;
+
+import com.google.inject.Inject;
+
+public class ServiceFaultResponseHandler extends 
BaseProfitBricksResponseHandler<ServiceFault> {
+
+   private final ServiceFault.Builder builder;
+   private boolean done = false;
+
+   @Inject
+   ServiceFaultResponseHandler(DateCodecFactory dateCodec) {
+      super(dateCodec);
+      this.builder = ServiceFault.builder();
+   }
+
+   @Override
+   protected void setPropertyOnEndTag(String qName) {
+      if ("faultCode".equals(qName))
+        
builder.faultCode(ServiceFault.FaultCode.fromValue(textToStringValue()));
+      else if ("httpCode".equals(qName))
+        builder.httpCode(textToIntValue());
+      else if ("message".equals(qName))
+        builder.message(textToStringValue());
+      else if ("requestId".equals(qName))
+        builder.requestId(textToIntValue());
+   }
+
+   @Override
+   public void endElement(String uri, String localName, String qName) throws 
SAXException {
+      if (done)
+        return;
+      setPropertyOnEndTag(qName);
+      if ("detail".equals(qName))
+        done = true;
+      clearTextBuffer();
+   }
+
+   @Override
+   public ServiceFault getResult() {
+      return builder.build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/BaseDataCenterResponseHandler.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/BaseDataCenterResponseHandler.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/BaseDataCenterResponseHandler.java
new file mode 100644
index 0000000..409131f
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/BaseDataCenterResponseHandler.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.http.parser.datacenter;
+
+import javax.inject.Inject;
+
+import org.jclouds.date.DateCodecFactory;
+import org.jclouds.profitbricks.domain.DataCenter;
+import org.jclouds.profitbricks.http.parser.BaseProfitBricksResponseHandler;
+
+public abstract class BaseDataCenterResponseHandler<T> extends 
BaseProfitBricksResponseHandler<T> {
+
+   protected DataCenter.Builder builder;
+
+   @Inject
+   BaseDataCenterResponseHandler(DateCodecFactory dateCodecFactory) {
+      super(dateCodecFactory);
+      this.builder = DataCenter.builder();
+   }
+
+   @Override
+   protected void setPropertyOnEndTag(String qName) {
+      if ("dataCenterId".equals(qName))
+        builder.id(textToStringValue());
+      else if ("dataCenterVersion".equals(qName))
+        builder.version(textToIntValue());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/DataCenterInfoResponseHandler.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/DataCenterInfoResponseHandler.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/DataCenterInfoResponseHandler.java
new file mode 100644
index 0000000..5b3aadd
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/DataCenterInfoResponseHandler.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.http.parser.datacenter;
+
+import org.jclouds.date.DateCodecFactory;
+import org.jclouds.profitbricks.domain.DataCenter;
+import org.jclouds.profitbricks.domain.Location;
+import org.jclouds.profitbricks.domain.ProvisioningState;
+import org.xml.sax.SAXException;
+
+import com.google.inject.Inject;
+
+public class DataCenterInfoResponseHandler extends 
BaseDataCenterResponseHandler<DataCenter> {
+
+   private boolean done = false;
+
+   @Inject
+   DataCenterInfoResponseHandler(DateCodecFactory dateCodecFactory) {
+      super(dateCodecFactory);
+   }
+
+   @Override
+   protected void setPropertyOnEndTag(String qName) {
+      super.setPropertyOnEndTag(qName);
+      if ("dataCenterName".equals(qName))
+        builder.name(textToStringValue());
+      else if ("location".equals(qName))
+        builder.location(Location.fromId(textToStringValue()));
+      else if ("provisioningState".equals(qName))
+        builder.state(ProvisioningState.fromValue(textToStringValue()));
+   }
+
+   @Override
+   public void endElement(String uri, String localName, String qName) throws 
SAXException {
+      if (done)
+        return;
+      setPropertyOnEndTag(qName);
+      if ("return".equals(qName))
+        done = true;
+      clearTextBuffer();
+   }
+
+   @Override
+   public DataCenter getResult() {
+      return builder.build();
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/DataCenterListResponseHandler.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/DataCenterListResponseHandler.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/DataCenterListResponseHandler.java
new file mode 100644
index 0000000..8b8ad1a
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/datacenter/DataCenterListResponseHandler.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.http.parser.datacenter;
+
+import java.util.List;
+
+import org.jclouds.date.DateCodecFactory;
+import org.jclouds.profitbricks.domain.DataCenter;
+import org.jclouds.profitbricks.domain.Location;
+import org.jclouds.profitbricks.domain.ProvisioningState;
+import org.xml.sax.SAXException;
+
+import com.google.common.collect.Lists;
+import com.google.inject.Inject;
+
+public class DataCenterListResponseHandler extends 
BaseDataCenterResponseHandler<List<DataCenter>> {
+
+   private final List<DataCenter> dataCenters;
+
+   @Inject
+   DataCenterListResponseHandler(DateCodecFactory dateCodec) {
+      super(dateCodec);
+      this.dataCenters = Lists.newArrayList();
+   }
+
+   @Override
+   public List<DataCenter> getResult() {
+      return dataCenters;
+   }
+
+   @Override
+   protected void setPropertyOnEndTag(String qName) {
+      super.setPropertyOnEndTag(qName);
+      if ("dataCenterName".equals(qName))
+        builder.name(textToStringValue());
+      else if ("location".equals(qName))
+        builder.location(Location.fromValue(textToStringValue()));
+      else if ("provisioningState".equals(qName))
+        builder.state(ProvisioningState.fromValue(textToStringValue()));
+   }
+
+   @Override
+   public void endElement(String uri, String localName, String qName) throws 
SAXException {
+      setPropertyOnEndTag(qName);
+      if ("return".equals(qName)) {
+        dataCenters.add(builder.build());
+        builder = DataCenter.builder();
+      }
+      clearTextBuffer();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/state/GetProvisioningStateResponseHandler.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/state/GetProvisioningStateResponseHandler.java
 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/state/GetProvisioningStateResponseHandler.java
new file mode 100644
index 0000000..705a918
--- /dev/null
+++ 
b/providers/profitbricks/src/main/java/org/jclouds/profitbricks/http/parser/state/GetProvisioningStateResponseHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.http.parser.state;
+
+import org.jclouds.date.DateCodecFactory;
+import org.jclouds.profitbricks.domain.ProvisioningState;
+import org.jclouds.profitbricks.http.parser.BaseProfitBricksResponseHandler;
+import org.xml.sax.SAXException;
+
+import com.google.inject.Inject;
+
+public class GetProvisioningStateResponseHandler extends 
BaseProfitBricksResponseHandler<ProvisioningState> {
+
+   private ProvisioningState state = ProvisioningState.UNRECOGNIZED;
+
+   @Inject
+   GetProvisioningStateResponseHandler(DateCodecFactory dateCodec) {
+      super(dateCodec);
+   }
+
+   @Override
+   public void endElement(String uri, String localName, String qName) throws 
SAXException {
+      setPropertyOnEndTag(qName);
+      clearTextBuffer();
+   }
+
+   @Override
+   protected void setPropertyOnEndTag(String qName) {
+      if ("return".equals(qName))
+        state = ProvisioningState.fromValue(textToStringValue());
+   }
+
+   @Override
+   public ProvisioningState getResult() {
+      return state;
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/test/java/org/jclouds/profitbricks/BaseProfitBricksLiveTest.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/test/java/org/jclouds/profitbricks/BaseProfitBricksLiveTest.java
 
b/providers/profitbricks/src/test/java/org/jclouds/profitbricks/BaseProfitBricksLiveTest.java
new file mode 100644
index 0000000..3ebc9c0
--- /dev/null
+++ 
b/providers/profitbricks/src/test/java/org/jclouds/profitbricks/BaseProfitBricksLiveTest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.apis.BaseApiLiveTest;
+import org.jclouds.profitbricks.compute.internal.ProvisioningStatusAware;
+import 
org.jclouds.profitbricks.compute.internal.ProvisioningStatusPollingPredicate;
+import org.jclouds.profitbricks.domain.ProvisioningState;
+import org.jclouds.util.Predicates2;
+
+import com.google.common.base.Predicate;
+
+public abstract class BaseProfitBricksLiveTest extends 
BaseApiLiveTest<ProfitBricksApi> {
+
+   protected Predicate<String> dcWaitingPredicate;
+
+   public BaseProfitBricksLiveTest() {
+      provider = "profitbricks";
+   }
+
+   @Override
+   protected void initialize() {
+      super.initialize();
+      this.dcWaitingPredicate = Predicates2.retry(
+             new ProvisioningStatusPollingPredicate(api, 
ProvisioningStatusAware.DATACENTER, ProvisioningState.AVAILABLE),
+             2l * 60l, 2l, TimeUnit.SECONDS);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/test/java/org/jclouds/profitbricks/ProfitBricksProviderMetadataTest.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/test/java/org/jclouds/profitbricks/ProfitBricksProviderMetadataTest.java
 
b/providers/profitbricks/src/test/java/org/jclouds/profitbricks/ProfitBricksProviderMetadataTest.java
new file mode 100644
index 0000000..210eeb9
--- /dev/null
+++ 
b/providers/profitbricks/src/test/java/org/jclouds/profitbricks/ProfitBricksProviderMetadataTest.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks;
+
+import org.jclouds.providers.internal.BaseProviderMetadataTest;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "ProfitBricksProviderMetadataTest")
+public class ProfitBricksProviderMetadataTest extends BaseProviderMetadataTest 
{
+
+   public ProfitBricksProviderMetadataTest() {
+      super(new ProfitBricksProviderMetadata(), new ProfitBricksApiMetadata());
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds/blob/cb45048a/providers/profitbricks/src/test/java/org/jclouds/profitbricks/binder/datacenter/CreateDataCenterRequestBinderTest.java
----------------------------------------------------------------------
diff --git 
a/providers/profitbricks/src/test/java/org/jclouds/profitbricks/binder/datacenter/CreateDataCenterRequestBinderTest.java
 
b/providers/profitbricks/src/test/java/org/jclouds/profitbricks/binder/datacenter/CreateDataCenterRequestBinderTest.java
new file mode 100644
index 0000000..b3a891b
--- /dev/null
+++ 
b/providers/profitbricks/src/test/java/org/jclouds/profitbricks/binder/datacenter/CreateDataCenterRequestBinderTest.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.profitbricks.binder.datacenter;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import org.jclouds.profitbricks.domain.DataCenter;
+import org.jclouds.profitbricks.domain.Location;
+import org.testng.annotations.Test;
+
+@Test(groups = "unit", testName = "CreateDataCenterRequestBinderTest")
+public class CreateDataCenterRequestBinderTest {
+
+   @Test
+   public void testCreatePayload() {
+      CreateDataCenterRequestBinder binder = new 
CreateDataCenterRequestBinder();
+
+      DataCenter.Request.CreatePayload payload = 
DataCenter.Request.CreatePayload.create("JClouds-DC", Location.DE_FKB);
+
+      String actual = binder.createPayload(payload);
+      assertNotNull(actual, "Binder returned null payload");
+      assertEquals(expectedPayload, actual);
+   }
+
+   private final String expectedPayload
+          = ("      <ws:createDataCenter>\n"
+          + "         <request>\n"
+          + "            <dataCenterName>JClouds-DC</dataCenterName>\n"
+          + "            <location>de/fkb</location>\n"
+          + "         </request>\n"
+          + "      </ws:createDataCenter>\n").replaceAll("\\s+", "");
+}

Reply via email to