diff --git a/core/src/main/resources/rest.properties b/core/src/main/resources/rest.properties
index 25219b9ca7..76cd22a9a7 100644
--- a/core/src/main/resources/rest.properties
+++ b/core/src/main/resources/rest.properties
@@ -183,6 +183,9 @@ softlayer.propertiesbuilder=org.jclouds.softlayer.SoftLayerPropertiesBuilder
glesys.contextbuilder=org.jclouds.glesys.GleSYSContextBuilder
glesys.propertiesbuilder=org.jclouds.glesys.GleSYSPropertiesBuilder
+opsource-servers.contextbuilder=org.jclouds.opsource.servers.OpSourceServersContextBuilder
+opsource-servers.propertiesbuilder=org.jclouds.opsource.servers.OpSourceServersPropertiesBuilder
+
savvis-symphonyvpdc.contextbuilder=org.jclouds.savvis.vpdc.VPDCContextBuilder
savvis-symphonyvpdc.propertiesbuilder=org.jclouds.savvis.vpdc.VPDCPropertiesBuilder
diff --git a/labs/opsource-servers/pom.xml b/labs/opsource-servers/pom.xml
new file mode 100644
index 0000000000..ef4eb9cb8a
--- /dev/null
+++ b/labs/opsource-servers/pom.xml
@@ -0,0 +1,137 @@
+
+
+
+ 4.0.0
+
+ org.jclouds
+ jclouds-project
+ 1.5.0-SNAPSHOT
+ ../../project/pom.xml
+
+ org.jclouds.labs
+ opsource-servers
+ jcloud opsource-servers api
+ jclouds components to access an implementation of OpSource Cloud Servers
+ bundle
+
+
+ https://api.opsourcecloud.net/oec/${jclouds.api-version}
+ 0.9
+
+ FIXME_USERNAME
+ FIXME_PASSWORD
+
+
+
+
+
+
+
+ org.jclouds
+ jclouds-compute
+ ${project.version}
+
+
+ org.jclouds
+ jclouds-core
+ ${project.version}
+ test-jar
+ test
+
+
+ org.jclouds
+ jclouds-compute
+ ${project.version}
+ test-jar
+ test
+
+
+ org.jclouds.driver
+ jclouds-sshj
+ ${project.version}
+ test
+
+
+ org.jclouds.driver
+ jclouds-log4j
+ ${project.version}
+ test
+
+
+
+
+
+ live
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration
+ integration-test
+
+ test
+
+
+
+ ${test.opsource-servers.endpoint}
+ ${test.opsource-servers.api-version}
+ ${test.opsource-servers.build-version}
+ ${test.opsource-servers.identity}
+ ${test.opsource-servers.credential}
+ ${test.opsource-servers.image-id}
+ ${test.opsource-servers.image.login-user}
+ ${test.opsource-servers.image.authenticate-sudo}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+
+
+ ${project.artifactId}
+ org.jclouds.vcloud.director.v1_5*;version="${project.version}"
+
+ org.jclouds.compute.internal;version="${project.version}",
+ org.jclouds.rest.internal;version="${project.version}",
+ org.jclouds*;version="${project.version}",
+ *
+
+
+
+
+
+
+
+
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceNameSpaces.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceNameSpaces.java
new file mode 100644
index 0000000000..474dd6d3a1
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceNameSpaces.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers;
+
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public interface OpSourceNameSpaces {
+ public static final String DIRECTORY = "http://oec.api.opsource.net/schemas/directory";
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersAsyncClient.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersAsyncClient.java
new file mode 100644
index 0000000000..2b07e18972
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersAsyncClient.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers;
+
+import org.jclouds.opsource.servers.features.AccountAsyncClient;
+import org.jclouds.rest.annotations.Delegate;
+
+/**
+ * Provides asynchronous access to OpSourceServers via their REST API.
+ *
+ * @see OpSourceServersClient
+ * @author Adrian Cole
+ */
+public interface OpSourceServersAsyncClient {
+
+ /**
+ * @return asynchronous access to {@link Account} features
+ */
+ @Delegate
+ AccountAsyncClient getAccountClient();
+
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersClient.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersClient.java
new file mode 100644
index 0000000000..16822419ff
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersClient.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.opsource.servers.features.AccountClient;
+import org.jclouds.rest.annotations.Delegate;
+
+/**
+ * Provides synchronous access to OpSourceServers.
+ *
+ * @see OpSourceServersAsyncClient
+ * @author Adrian Cole
+ */
+@Timeout(duration = 60, timeUnit = TimeUnit.SECONDS)
+public interface OpSourceServersClient {
+
+ /**
+ * @return synchronous access to {@link Account} features
+ */
+ @Delegate
+ AccountClient getAccountClient();
+
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersContextBuilder.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersContextBuilder.java
new file mode 100644
index 0000000000..5c8cf97d26
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersContextBuilder.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers;
+
+import java.util.List;
+import java.util.Properties;
+
+import org.jclouds.rest.RestContextBuilder;
+import org.jclouds.opsource.servers.config.OpSourceServersRestClientModule;
+
+import com.google.inject.Module;
+
+/**
+ * @author Adrian Cole
+ */
+public class OpSourceServersContextBuilder extends RestContextBuilder {
+
+ public OpSourceServersContextBuilder(Properties props) {
+ super(OpSourceServersClient.class, OpSourceServersAsyncClient.class, props);
+ }
+
+ @Override
+ protected void addClientModule(List modules) {
+ modules.add(new OpSourceServersRestClientModule());
+ }
+
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersPropertiesBuilder.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersPropertiesBuilder.java
new file mode 100644
index 0000000000..28cc359507
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/OpSourceServersPropertiesBuilder.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers;
+
+import static org.jclouds.Constants.PROPERTY_API_VERSION;
+import static org.jclouds.Constants.PROPERTY_ENDPOINT;
+
+import java.util.Properties;
+
+import org.jclouds.PropertiesBuilder;
+
+/**
+ * Builds properties used in OpSourceServers clients
+ *
+ * @author Adrian Cole
+ */
+public class OpSourceServersPropertiesBuilder extends PropertiesBuilder {
+
+ @Override
+ public Properties defaultProperties() {
+ Properties properties = super.defaultProperties();
+ properties.setProperty(PROPERTY_ENDPOINT, "https://api.opsourcecloud.net/oec/${jclouds.api-version}");
+ properties.setProperty(PROPERTY_API_VERSION, "0.9");
+ return properties;
+ }
+
+ public OpSourceServersPropertiesBuilder(Properties properties) {
+ super(properties);
+ }
+
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/config/OpSourceServersRestClientModule.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/config/OpSourceServersRestClientModule.java
new file mode 100644
index 0000000000..736526e296
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/config/OpSourceServersRestClientModule.java
@@ -0,0 +1,69 @@
+/**
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.config;
+
+import java.util.Map;
+
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.RequiresHttp;
+import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.annotation.Redirection;
+import org.jclouds.http.annotation.ServerError;
+import org.jclouds.location.suppliers.ImplicitLocationSupplier;
+import org.jclouds.location.suppliers.implicit.OnlyLocationOrFirstZone;
+import org.jclouds.opsource.servers.OpSourceServersAsyncClient;
+import org.jclouds.opsource.servers.OpSourceServersClient;
+import org.jclouds.opsource.servers.features.AccountAsyncClient;
+import org.jclouds.opsource.servers.features.AccountClient;
+import org.jclouds.opsource.servers.handlers.OpSourceServersErrorHandler;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.config.RestClientModule;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Scopes;
+
+/**
+ * Configures the OpSourceServers connection.
+ *
+ * @author Adrian Cole
+ */
+@RequiresHttp
+@ConfiguresRestClient
+public class OpSourceServersRestClientModule extends
+ RestClientModule {
+
+ public static final Map, Class>> DELEGATE_MAP = ImmutableMap., Class>> builder()//
+ .put(AccountClient.class, AccountAsyncClient.class).build();
+
+ public OpSourceServersRestClientModule() {
+ super(OpSourceServersClient.class, OpSourceServersAsyncClient.class, DELEGATE_MAP);
+ }
+
+ @Override
+ protected void bindErrorHandlers() {
+ bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(OpSourceServersErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(OpSourceServersErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(OpSourceServersErrorHandler.class);
+ }
+
+ @Override
+ protected void installLocations() {
+ super.installLocations();
+ bind(ImplicitLocationSupplier.class).to(OnlyLocationOrFirstZone.class).in(Scopes.SINGLETON);
+ }
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/domain/Account.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/domain/Account.java
new file mode 100644
index 0000000000..43d8e88b3f
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/domain/Account.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.domain;
+
+import static com.google.common.base.Objects.equal;
+import static org.jclouds.opsource.servers.OpSourceNameSpaces.DIRECTORY;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.google.common.base.Objects;
+
+/**
+ *
+ *
+ */
+@XmlRootElement(name = "Account", namespace = DIRECTORY)
+public class Account {
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return new Builder().fromAccount(this);
+ }
+
+ public static class Builder {
+
+ private String orgId;
+
+ /**
+ * @see Account#getOrgId()
+ */
+ public Builder orgId(String orgId) {
+ this.orgId = orgId;
+ return this;
+ }
+
+ public Account build() {
+ return new Account(orgId);
+ }
+
+ public Builder fromAccount(Account in) {
+ return orgId(in.getOrgId());
+ }
+ }
+
+ private Account() {
+ // For JAXB and builder use
+ }
+
+ @XmlElement(namespace = DIRECTORY)
+ protected String orgId;
+
+ private Account(String orgId) {
+ this.orgId = orgId;
+ }
+
+ /**
+ *
+ * @return your Organization ID that will be used as the basis for subsequent
+ * API interactions
+ *
+ */
+ public String getOrgId() {
+ return orgId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ Account that = Account.class.cast(o);
+ return equal(orgId, that.orgId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(orgId);
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toStringHelper("").add("orgId", orgId).toString();
+ }
+
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/features/AccountAsyncClient.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/features/AccountAsyncClient.java
new file mode 100644
index 0000000000..7c3f8fbb9c
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/features/AccountAsyncClient.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.features;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.opsource.servers.domain.Account;
+import org.jclouds.rest.annotations.JAXBResponseParser;
+import org.jclouds.rest.annotations.RequestFilters;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * @see AccountClient
+ * @author Adrian Cole
+ */
+@RequestFilters(BasicAuthentication.class)
+public interface AccountAsyncClient {
+
+ /**
+ * @see AccountClient#getMyAccount()
+ */
+ @GET
+ @Path("/myaccount")
+ @Consumes
+ @JAXBResponseParser
+ ListenableFuture getMyAccount();
+
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/features/AccountClient.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/features/AccountClient.java
new file mode 100644
index 0000000000..1495a87924
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/features/AccountClient.java
@@ -0,0 +1,44 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.features;
+
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.opsource.servers.domain.Account;
+
+/**
+ * Provides synchronous access to Account.
+ *
+ *
+ * @see AccountAsyncClient
+ * @author Adrian Cole
+ */
+@Timeout(duration = 180, timeUnit = TimeUnit.SECONDS)
+public interface AccountClient {
+
+ /**
+ * Before you can begin using the range of Server, Network and Image APIs,
+ * you will need to first obtain your organization details.
+ *
+ * @return the user's details, including their organization ID.
+ */
+ Account getMyAccount();
+
+}
diff --git a/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/handlers/OpSourceServersErrorHandler.java b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/handlers/OpSourceServersErrorHandler.java
new file mode 100644
index 0000000000..d3d905b400
--- /dev/null
+++ b/labs/opsource-servers/src/main/java/org/jclouds/opsource/servers/handlers/OpSourceServersErrorHandler.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.handlers;
+
+import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.HttpResponseException;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ *
+ * @author Adrian Cole
+ *
+ */
+@Singleton
+public class OpSourceServersErrorHandler implements HttpErrorHandler {
+
+ public void handleError(HttpCommand command, HttpResponse response) {
+ // it is important to always read fully and close streams
+ byte[] data = closeClientButKeepContentStream(response);
+ String message = data != null ? new String(data) : null;
+
+ Exception exception = message != null ? new HttpResponseException(command, response, message)
+ : new HttpResponseException(command, response);
+ message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+ response.getStatusLine());
+ switch (response.getStatusCode()) {
+ case 401:
+ exception = new AuthorizationException(message, exception);
+ break;
+ case 404:
+ if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+ exception = new ResourceNotFoundException(message, exception);
+ }
+ break;
+ default:
+ exception = new HttpResponseException(command, response, message);
+ break;
+ }
+ command.setException(exception);
+ }
+
+}
diff --git a/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/OpSourceServersClientExperimentLiveTest.java b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/OpSourceServersClientExperimentLiveTest.java
new file mode 100644
index 0000000000..584a74709d
--- /dev/null
+++ b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/OpSourceServersClientExperimentLiveTest.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers;
+
+import org.jclouds.opsource.servers.domain.Account;
+import org.jclouds.opsource.servers.internal.BaseOpSourceServersClientLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "live", testName = "OpSourceServersClientExperimentLiveTest")
+public class OpSourceServersClientExperimentLiveTest extends BaseOpSourceServersClientLiveTest {
+
+ public void testImplicitSession() {
+ Account account = context.getApi().getAccountClient().getMyAccount();
+ assert account.getOrgId() != null;
+ }
+
+}
diff --git a/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/features/AccountClientExpectTest.java b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/features/AccountClientExpectTest.java
new file mode 100644
index 0000000000..c0e759c0ee
--- /dev/null
+++ b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/features/AccountClientExpectTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.features;
+
+import static org.testng.Assert.assertEquals;
+
+import java.net.URI;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.opsource.servers.OpSourceServersClient;
+import org.jclouds.opsource.servers.domain.Account;
+import org.jclouds.opsource.servers.internal.BaseOpSourceServersRestClientExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMultimap;
+
+/**
+ * Allows us to test the {@link AccountClient} via its side effects.
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = { "unit" }, singleThreaded = true, testName = "AccountClientExpectTest")
+public class AccountClientExpectTest extends BaseOpSourceServersRestClientExpectTest {
+
+ @Test
+ public void testGetMyAccount() {
+ OpSourceServersClient client = requestSendsResponse(
+ HttpRequest
+ .builder()
+ .method("GET")
+ .endpoint(URI.create("https://api.opsourcecloud.net/oec/0.9/myaccount"))
+ .headers(
+ ImmutableMultimap. builder().put("Accept", "*/*")
+ .put("Authorization", "Basic dXNlcjpwYXNzd29yZA==").build()).build(),
+
+ HttpResponse.builder().statusCode(200).payload(payloadFromResource("/myaccount.xml")).build());
+
+ Account expected = Account.builder().orgId("8a8f6abc-2745-4d8a-9cbc-8dabe5a7d0e4").build();
+
+ assertEquals(client.getAccountClient().getMyAccount(), expected);
+ }
+
+}
diff --git a/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/features/AccountClientLiveTest.java b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/features/AccountClientLiveTest.java
new file mode 100644
index 0000000000..a2c2bf3ccb
--- /dev/null
+++ b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/features/AccountClientLiveTest.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.features;
+
+import org.jclouds.opsource.servers.domain.Account;
+import org.jclouds.opsource.servers.internal.BaseOpSourceServersClientLiveTest;
+import org.testng.annotations.Test;
+
+/**
+ * Tests live behavior of {@link AccountClient}.
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = { "live" }, singleThreaded = true, testName = "AccountClientLiveTest")
+public class AccountClientLiveTest extends BaseOpSourceServersClientLiveTest {
+
+ public void testGetMyAccount() {
+ Account account = context.getApi().getAccountClient().getMyAccount();
+ assert account.getOrgId() != null;
+ }
+
+}
diff --git a/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/handlers/OpSourceServersErrorHandlerTest.java b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/handlers/OpSourceServersErrorHandlerTest.java
new file mode 100644
index 0000000000..9022e802b9
--- /dev/null
+++ b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/handlers/OpSourceServersErrorHandlerTest.java
@@ -0,0 +1,105 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.handlers;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reportMatcher;
+import static org.easymock.EasyMock.verify;
+
+import java.net.URI;
+
+import org.easymock.IArgumentMatcher;
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.io.Payloads;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.jclouds.util.Strings2;
+import org.testng.annotations.Test;
+
+import com.google.inject.Guice;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = { "unit" })
+public class OpSourceServersErrorHandlerTest {
+
+ @Test
+ public void test401MakesAuthorizationException() {
+ assertCodeMakes("GET", URI.create("https://api.opsourcecloud.net/oec/0.9/foo"), 401, "", "Unauthorized",
+ AuthorizationException.class);
+ }
+
+ @Test
+ public void test404MakesResourceNotFoundException() {
+ assertCodeMakes("GET", URI.create("https://api.opsourcecloud.net/oec/0.9/foo"), 404, "", "Not Found",
+ ResourceNotFoundException.class);
+ }
+
+ private void assertCodeMakes(String method, URI uri, int statusCode, String message, String content,
+ Class extends Exception> expected) {
+ assertCodeMakes(method, uri, statusCode, message, "text/xml", content, expected);
+ }
+
+ private void assertCodeMakes(String method, URI uri, int statusCode, String message, String contentType,
+ String content, Class extends Exception> expected) {
+
+ OpSourceServersErrorHandler function = Guice.createInjector().getInstance(OpSourceServersErrorHandler.class);
+
+ HttpCommand command = createMock(HttpCommand.class);
+ HttpRequest request = new HttpRequest(method, uri);
+ HttpResponse response = new HttpResponse(statusCode, message, Payloads.newInputStreamPayload(Strings2
+ .toInputStream(content)));
+ response.getPayload().getContentMetadata().setContentType(contentType);
+
+ expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
+ command.setException(classEq(expected));
+
+ replay(command);
+
+ function.handleError(command, response);
+
+ verify(command);
+ }
+
+ public static Exception classEq(final Class extends Exception> in) {
+ reportMatcher(new IArgumentMatcher() {
+
+ @Override
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("classEq(");
+ buffer.append(in);
+ buffer.append(")");
+ }
+
+ @Override
+ public boolean matches(Object arg) {
+ return arg.getClass() == in;
+ }
+
+ });
+ return null;
+ }
+
+}
diff --git a/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/internal/BaseOpSourceServersClientLiveTest.java b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/internal/BaseOpSourceServersClientLiveTest.java
new file mode 100644
index 0000000000..9aba439acb
--- /dev/null
+++ b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/internal/BaseOpSourceServersClientLiveTest.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.internal;
+
+import java.util.Properties;
+
+import org.jclouds.compute.BaseVersionedServiceLiveTest;
+import org.jclouds.logging.log4j.config.Log4JLoggingModule;
+import org.jclouds.opsource.servers.OpSourceServersAsyncClient;
+import org.jclouds.opsource.servers.OpSourceServersClient;
+import org.jclouds.rest.RestContext;
+import org.jclouds.rest.RestContextFactory;
+import org.jclouds.sshj.config.SshjSshClientModule;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Tests behavior of {@link OpSourceServersClient} and acts as parent for other
+ * client live tests.
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "live")
+public abstract class BaseOpSourceServersClientLiveTest extends BaseVersionedServiceLiveTest {
+
+ protected BaseOpSourceServersClientLiveTest() {
+ provider = "opsource-servers";
+ }
+
+ protected RestContext context;
+
+ @BeforeClass(groups = { "live" })
+ public void setupContext() {
+ setupCredentials();
+ Properties overrides = setupProperties();
+
+ context = new RestContextFactory().createContext(provider, identity, credential,
+ ImmutableSet. of(new Log4JLoggingModule(), new SshjSshClientModule()), overrides);
+ }
+
+ protected void tearDown() {
+ if (context != null)
+ context.close();
+ }
+}
diff --git a/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/internal/BaseOpSourceServersRestClientExpectTest.java b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/internal/BaseOpSourceServersRestClientExpectTest.java
new file mode 100644
index 0000000000..c5720cd222
--- /dev/null
+++ b/labs/opsource-servers/src/test/java/org/jclouds/opsource/servers/internal/BaseOpSourceServersRestClientExpectTest.java
@@ -0,0 +1,37 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.opsource.servers.internal;
+
+import org.jclouds.opsource.servers.OpSourceServersClient;
+import org.jclouds.rest.BaseRestClientExpectTest;
+
+/**
+ * Base class for writing OpSourceServersClient Expect tests
+ *
+ * @author Adrian Cole
+ */
+public class BaseOpSourceServersRestClientExpectTest extends BaseRestClientExpectTest {
+
+ public BaseOpSourceServersRestClientExpectTest() {
+ provider = "opsource-servers";
+ identity = "user";
+ credential = "password";
+ }
+
+}
diff --git a/labs/opsource-servers/src/test/resources/log4j.xml b/labs/opsource-servers/src/test/resources/log4j.xml
new file mode 100644
index 0000000000..63810d3ca0
--- /dev/null
+++ b/labs/opsource-servers/src/test/resources/log4j.xml
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/labs/opsource-servers/src/test/resources/myaccount.xml b/labs/opsource-servers/src/test/resources/myaccount.xml
new file mode 100644
index 0000000000..afc9b1107c
--- /dev/null
+++ b/labs/opsource-servers/src/test/resources/myaccount.xml
@@ -0,0 +1,32 @@
+
+
+ testuser
+ Test User
+ Test
+ User
+ test@example.com
+ 8a8f6abc-2745-4d8a-9cbc-8dabe5a7d0e4
+
+
+ create image
+
+
+ reports
+
+
+ server
+
+
+ primary administrator
+
+
+ network
+
+
+
\ No newline at end of file
diff --git a/labs/pom.xml b/labs/pom.xml
index 62213128e1..ad0519c072 100644
--- a/labs/pom.xml
+++ b/labs/pom.xml
@@ -36,5 +36,6 @@
virtualbox
vcloud-director
glesys
+ opsource-servers