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+", ""); +}
