diff --git a/sandbox-providers/softlayer/pom.xml b/sandbox-providers/softlayer/pom.xml
new file mode 100644
index 0000000000..52c3a524e5
--- /dev/null
+++ b/sandbox-providers/softlayer/pom.xml
@@ -0,0 +1,129 @@
+
+
+
+ 4.0.0
+
+ org.jclouds
+ jclouds-project
+ 1.0-SNAPSHOT
+ ../../project/pom.xml
+
+ org.jclouds.provider
+ softlayer
+ jclouds SoftLayer core
+ jclouds components to access SoftLayer
+
+
+
+ jclouds-sona-snapshots-nexus
+ https://oss.sonatype.org/content/repositories/snapshots
+
+ false
+
+
+ true
+
+
+
+
+
+ https://api.softlayer.com/rest
+ 3
+ FIXME
+ FIXME
+
+
+
+ org.jclouds
+ jclouds-core
+ ${project.version}
+
+
+ org.jclouds
+ jclouds-core
+ ${project.version}
+ test-jar
+ test
+
+
+ log4j
+ log4j
+ 1.2.16
+ test
+
+
+ org.jclouds.driver
+ jclouds-log4j
+ ${project.version}
+ test
+
+
+
+
+ live
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration
+ integration-test
+
+ test
+
+
+
+
+ test.softlayer.endpoint
+ ${test.softlayer.endpoint}
+
+
+ test.softlayer.apiversion
+ ${test.softlayer.apiversion}
+
+
+ test.softlayer.identity
+ ${test.softlayer.identity}
+
+
+ test.softlayer.credential
+ ${test.softlayer.credential}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerAsyncClient.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerAsyncClient.java
new file mode 100644
index 0000000000..0205a16710
--- /dev/null
+++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerAsyncClient.java
@@ -0,0 +1,68 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer;
+
+import java.util.Set;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.rest.annotations.ExceptionParser;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.softlayer.domain.VirtualGuest;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Provides asynchronous access to SoftLayer via their REST API.
+ *
+ *
+ * @see SoftLayerClient
+ * @see
+ * @author Adrian Cole
+ */
+@RequestFilters(BasicAuthentication.class)
+@Path("/v{jclouds.api-version}")
+public interface SoftLayerAsyncClient {
+
+ /**
+ * @see SoftLayerClient#listVirtualGuests
+ */
+ @GET
+ @Path("/SoftLayer_Account/VirtualGuests.json")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
+ ListenableFuture> listVirtualGuests();
+
+ /**
+ * @see SoftLayerClient#getVirtualGuest
+ */
+ @GET
+ @Path("/SoftLayer_Virtual_Guest/{id}.json")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ ListenableFuture getVirtualGuest(@PathParam("id") long id);
+}
diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerClient.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerClient.java
new file mode 100644
index 0000000000..46f5fafa02
--- /dev/null
+++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerClient.java
@@ -0,0 +1,53 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.concurrent.Timeout;
+import org.jclouds.softlayer.domain.VirtualGuest;
+
+/**
+ * Provides synchronous access to SoftLayer.
+ *
+ *
+ * @see SoftLayerAsyncClient
+ * @see
+ * @author Adrian Cole
+ */
+@Timeout(duration = 4, timeUnit = TimeUnit.SECONDS)
+public interface SoftLayerClient {
+
+ /**
+ *
+ * @return an account's associated virtual guest objects.
+ */
+ Set listVirtualGuests();
+
+ /**
+ *
+ * @param id
+ * id of the virtual guest
+ * @return virtual guest or null if not found
+ */
+ VirtualGuest getVirtualGuest(long id);
+
+}
diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerContextBuilder.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerContextBuilder.java
new file mode 100644
index 0000000000..e97f4914ba
--- /dev/null
+++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerContextBuilder.java
@@ -0,0 +1,45 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer;
+
+import java.util.List;
+import java.util.Properties;
+
+import org.jclouds.softlayer.config.SoftLayerRestClientModule;
+import org.jclouds.rest.RestContextBuilder;
+
+import com.google.inject.Module;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+public class SoftLayerContextBuilder extends
+ RestContextBuilder {
+
+ public SoftLayerContextBuilder(Properties props) {
+ super(SoftLayerClient.class, SoftLayerAsyncClient.class, props);
+ }
+
+ protected void addClientModule(List modules) {
+ modules.add(new SoftLayerRestClientModule());
+ }
+
+}
diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerPropertiesBuilder.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerPropertiesBuilder.java
new file mode 100644
index 0000000000..dd2451c2df
--- /dev/null
+++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/SoftLayerPropertiesBuilder.java
@@ -0,0 +1,47 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer;
+
+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 SoftLayer Clients
+ *
+ * @author Adrian Cole
+ */
+public class SoftLayerPropertiesBuilder extends PropertiesBuilder {
+ @Override
+ protected Properties defaultProperties() {
+ Properties properties = super.defaultProperties();
+ properties.setProperty(PROPERTY_ENDPOINT, "https://api.softlayer.com/rest");
+ properties.setProperty(PROPERTY_API_VERSION, "3");
+ return properties;
+ }
+
+ public SoftLayerPropertiesBuilder(Properties properties) {
+ super(properties);
+ }
+
+}
diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/config/SoftLayerRestClientModule.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/config/SoftLayerRestClientModule.java
new file mode 100644
index 0000000000..0de8505212
--- /dev/null
+++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/config/SoftLayerRestClientModule.java
@@ -0,0 +1,68 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer.config;
+
+import org.jclouds.http.HttpErrorHandler;
+import org.jclouds.http.HttpRetryHandler;
+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.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.json.config.GsonModule.DateAdapter;
+import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.rest.config.RestClientModule;
+import org.jclouds.softlayer.SoftLayerAsyncClient;
+import org.jclouds.softlayer.SoftLayerClient;
+import org.jclouds.softlayer.handlers.SoftLayerErrorHandler;
+
+/**
+ * Configures the SoftLayer connection.
+ *
+ * @author Adrian Cole
+ */
+@RequiresHttp
+@ConfiguresRestClient
+public class SoftLayerRestClientModule extends RestClientModule {
+
+ public SoftLayerRestClientModule() {
+ super(SoftLayerClient.class, SoftLayerAsyncClient.class);
+ }
+
+ @Override
+ protected void configure() {
+ bind(DateAdapter.class).to(Iso8601DateAdapter.class);
+ super.configure();
+ }
+
+ @Override
+ protected void bindErrorHandlers() {
+ bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(SoftLayerErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(SoftLayerErrorHandler.class);
+ bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(SoftLayerErrorHandler.class);
+ }
+
+ @Override
+ protected void bindRetryHandlers() {
+ bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(BackoffLimitedRetryHandler.class);
+ }
+
+}
diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/domain/VirtualGuest.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/domain/VirtualGuest.java
new file mode 100644
index 0000000000..031c034c61
--- /dev/null
+++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/domain/VirtualGuest.java
@@ -0,0 +1,397 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Date;
+
+import com.google.common.base.CaseFormat;
+import com.google.gson.annotations.SerializedName;
+
+/**
+ * The virtual guest data type presents the structure in which all virtual guests will be presented.
+ * Internally, the structure supports various virtualization platforms with no change to external
+ * interaction.
+ * A guest, also known as a virtual server or CloudLayer Computing Instance, represents an
+ * allocation of resources on a virtual host.
+ *
+ * @author Adrian Cole
+ * @see
+ */
+public class VirtualGuest implements Comparable {
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ }
+
+ public static enum State {
+ STARTING, RUNNING, STOPPING, STOPPED, DESTROYED, EXPUNGING, MIGRATING, ERROR, UNKNOWN, SHUTDOWNED, UNRECOGNIZED;
+ @Override
+ public String toString() {
+ return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, name());
+ }
+
+ public static State fromValue(String state) {
+ try {
+ return valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, checkNotNull(state, "state")));
+ } catch (IllegalArgumentException e) {
+ return UNRECOGNIZED;
+ }
+ }
+
+ }
+
+ private long accountId = -1;
+ private Date createDate;
+ @SerializedName("dedicatedAccountHostOnlyFlag")
+ private boolean dedicatedAccountHostOnly;
+ private String domain;
+ private String fullyQualifiedDomainName;
+ private String hostname;
+ private long id = -1;
+ private Date lastVerifiedDate;
+ private int maxCpu = -1;
+ private String maxCpuUnits;
+ private int maxMemory = -1;
+ private Date metricPollDate;
+ private Date modifyDate;
+ private String notes;
+ @SerializedName("privateNetworkOnlyFlag")
+ private boolean privateNetworkOnly;
+ private int startCpus = -1;
+ private int statusId = -1;
+ private String uuid;
+ private String primaryBackendIpAddress;
+ private String primaryIpAddress;
+
+ // for deserializer
+ VirtualGuest() {
+
+ }
+
+ public VirtualGuest(long accountId, Date createDate, boolean dedicatedAccountHostOnly, String domain,
+ String fullyQualifiedDomainName, String hostname, long id, Date lastVerifiedDate, int maxCpu,
+ String maxCpuUnits, int maxMemory, Date metricPollDate, Date modifyDate, String notes,
+ boolean privateNetworkOnly, int startCpus, int statusId, String uuid, String primaryBackendIpAddress,
+ String primaryIpAddress) {
+ this.accountId = accountId;
+ this.createDate = createDate;
+ this.dedicatedAccountHostOnly = dedicatedAccountHostOnly;
+ this.domain = domain;
+ this.fullyQualifiedDomainName = fullyQualifiedDomainName;
+ this.hostname = hostname;
+ this.id = id;
+ this.lastVerifiedDate = lastVerifiedDate;
+ this.maxCpu = maxCpu;
+ this.maxCpuUnits = maxCpuUnits;
+ this.maxMemory = maxMemory;
+ this.metricPollDate = metricPollDate;
+ this.modifyDate = modifyDate;
+ this.notes = notes;
+ this.privateNetworkOnly = privateNetworkOnly;
+ this.startCpus = startCpus;
+ this.statusId = statusId;
+ this.uuid = uuid;
+ this.primaryBackendIpAddress = primaryBackendIpAddress;
+ this.primaryIpAddress = primaryIpAddress;
+ }
+
+ @Override
+ public int compareTo(VirtualGuest arg0) {
+ return new Long(id).compareTo(arg0.getId());
+ }
+
+ /**
+ * @return A computing instance's associated account id
+ */
+ public long getAccountId() {
+ return accountId;
+ }
+
+ /**
+ * @return The date a virtual computing instance was created.
+ */
+ public Date getCreateDate() {
+ return createDate;
+ }
+
+ /**
+ * @return When true this flag specifies that a compute instance is to run on hosts that only
+ * have guests from the same account.
+ */
+ public boolean isDedicatedAccountHostOnly() {
+ return dedicatedAccountHostOnly;
+ }
+
+ /**
+ * @return A computing instance's domain name
+ */
+ public String getDomain() {
+ return domain;
+ }
+
+ /**
+ * @return A name reflecting the hostname and domain of the computing instance.
+ */
+ public String getFullyQualifiedDomainName() {
+ return fullyQualifiedDomainName;
+ }
+
+ /**
+ * @return A virtual computing instance's hostname
+ */
+ public String getHostname() {
+ return hostname;
+ }
+
+ /**
+ * @return Unique ID for a computing instance.
+ */
+ public long getId() {
+ return id;
+ }
+
+ /**
+ * @return The last timestamp of when the guest was verified as a resident virtual machine on the
+ * host's hypervisor platform.
+ */
+
+ public Date getLastVerifiedDate() {
+ return lastVerifiedDate;
+ }
+
+ /**
+ * @return The maximum amount of CPU resources a computing instance may utilize.
+ */
+ public int getMaxCpu() {
+ return maxCpu;
+ }
+
+ /**
+ * @return The unit of the maximum amount of CPU resources a computing instance may utilize.
+ */
+ public String getMaxCpuUnits() {
+ return maxCpuUnits;
+ }
+
+ /**
+ * @return The maximum amount of memory a computing instance may utilize.
+ */
+ public int getMaxMemory() {
+ return maxMemory;
+ }
+
+ /**
+ * @return The date of the most recent metric tracking poll performed.
+ */
+ public Date getMetricPollDate() {
+ return metricPollDate;
+ }
+
+ /**
+ * @return The date a virtual computing instance was last modified.
+ */
+ public Date getModifyDate() {
+ return modifyDate;
+ }
+
+ /**
+ * @return A small note about a cloud instance to use at your discretion.
+ */
+ public String getNotes() {
+ return notes;
+ }
+
+ /**
+ * @return Whether the computing instance only has access to the private network.
+ */
+ public boolean isPrivateNetworkOnly() {
+ return privateNetworkOnly;
+ }
+
+ /**
+ * @return The number of CPUs available to a computing instance upon startup.
+ */
+ public int getStartCpus() {
+ return startCpus;
+ }
+
+ /**
+ * @return A computing instances status ID
+ */
+ public int getStatusId() {
+ return statusId;
+ }
+
+ /**
+ * @return Unique ID for a computing instance's record on a virtualization platform.
+ */
+ public String getUuid() {
+ return uuid;
+ }
+
+ /**
+ * @return private ip address
+ */
+ public String getPrimaryBackendIpAddress() {
+ return primaryBackendIpAddress;
+ }
+
+ /**
+ * @return public ip address
+ */
+ public String getPrimaryIpAddress() {
+ return primaryIpAddress;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (int) (accountId ^ (accountId >>> 32));
+ result = prime * result + ((createDate == null) ? 0 : createDate.hashCode());
+ result = prime * result + (dedicatedAccountHostOnly ? 1231 : 1237);
+ result = prime * result + ((domain == null) ? 0 : domain.hashCode());
+ result = prime * result + ((fullyQualifiedDomainName == null) ? 0 : fullyQualifiedDomainName.hashCode());
+ result = prime * result + ((hostname == null) ? 0 : hostname.hashCode());
+ result = prime * result + (int) (id ^ (id >>> 32));
+ result = prime * result + ((lastVerifiedDate == null) ? 0 : lastVerifiedDate.hashCode());
+ result = prime * result + maxCpu;
+ result = prime * result + ((maxCpuUnits == null) ? 0 : maxCpuUnits.hashCode());
+ result = prime * result + maxMemory;
+ result = prime * result + ((metricPollDate == null) ? 0 : metricPollDate.hashCode());
+ result = prime * result + ((modifyDate == null) ? 0 : modifyDate.hashCode());
+ result = prime * result + ((notes == null) ? 0 : notes.hashCode());
+ result = prime * result + ((primaryBackendIpAddress == null) ? 0 : primaryBackendIpAddress.hashCode());
+ result = prime * result + ((primaryIpAddress == null) ? 0 : primaryIpAddress.hashCode());
+ result = prime * result + (privateNetworkOnly ? 1231 : 1237);
+ result = prime * result + startCpus;
+ result = prime * result + statusId;
+ result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ VirtualGuest other = (VirtualGuest) obj;
+ if (accountId != other.accountId)
+ return false;
+ if (createDate == null) {
+ if (other.createDate != null)
+ return false;
+ } else if (!createDate.equals(other.createDate))
+ return false;
+ if (dedicatedAccountHostOnly != other.dedicatedAccountHostOnly)
+ return false;
+ if (domain == null) {
+ if (other.domain != null)
+ return false;
+ } else if (!domain.equals(other.domain))
+ return false;
+ if (fullyQualifiedDomainName == null) {
+ if (other.fullyQualifiedDomainName != null)
+ return false;
+ } else if (!fullyQualifiedDomainName.equals(other.fullyQualifiedDomainName))
+ return false;
+ if (hostname == null) {
+ if (other.hostname != null)
+ return false;
+ } else if (!hostname.equals(other.hostname))
+ return false;
+ if (id != other.id)
+ return false;
+ if (lastVerifiedDate == null) {
+ if (other.lastVerifiedDate != null)
+ return false;
+ } else if (!lastVerifiedDate.equals(other.lastVerifiedDate))
+ return false;
+ if (maxCpu != other.maxCpu)
+ return false;
+ if (maxCpuUnits == null) {
+ if (other.maxCpuUnits != null)
+ return false;
+ } else if (!maxCpuUnits.equals(other.maxCpuUnits))
+ return false;
+ if (maxMemory != other.maxMemory)
+ return false;
+ if (metricPollDate == null) {
+ if (other.metricPollDate != null)
+ return false;
+ } else if (!metricPollDate.equals(other.metricPollDate))
+ return false;
+ if (modifyDate == null) {
+ if (other.modifyDate != null)
+ return false;
+ } else if (!modifyDate.equals(other.modifyDate))
+ return false;
+ if (notes == null) {
+ if (other.notes != null)
+ return false;
+ } else if (!notes.equals(other.notes))
+ return false;
+ if (primaryBackendIpAddress == null) {
+ if (other.primaryBackendIpAddress != null)
+ return false;
+ } else if (!primaryBackendIpAddress.equals(other.primaryBackendIpAddress))
+ return false;
+ if (primaryIpAddress == null) {
+ if (other.primaryIpAddress != null)
+ return false;
+ } else if (!primaryIpAddress.equals(other.primaryIpAddress))
+ return false;
+ if (privateNetworkOnly != other.privateNetworkOnly)
+ return false;
+ if (startCpus != other.startCpus)
+ return false;
+ if (statusId != other.statusId)
+ return false;
+ if (uuid == null) {
+ if (other.uuid != null)
+ return false;
+ } else if (!uuid.equals(other.uuid))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "[accountId=" + accountId + ", createDate=" + createDate + ", dedicatedAccountHostOnly="
+ + dedicatedAccountHostOnly + ", domain=" + domain + ", fullyQualifiedDomainName="
+ + fullyQualifiedDomainName + ", hostname=" + hostname + ", id=" + id + ", lastVerifiedDate="
+ + lastVerifiedDate + ", maxCpu=" + maxCpu + ", maxCpuUnits=" + maxCpuUnits + ", maxMemory=" + maxMemory
+ + ", metricPollDate=" + metricPollDate + ", modifyDate=" + modifyDate + ", notes=" + notes
+ + ", primaryBackendIpAddress=" + primaryBackendIpAddress + ", primaryIpAddress=" + primaryIpAddress
+ + ", privateNetworkOnly=" + privateNetworkOnly + ", startCpus=" + startCpus + ", statusId=" + statusId
+ + ", uuid=" + uuid + "]";
+ }
+
+}
diff --git a/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/handlers/SoftLayerErrorHandler.java b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/handlers/SoftLayerErrorHandler.java
new file mode 100644
index 0000000000..72bb689893
--- /dev/null
+++ b/sandbox-providers/softlayer/src/main/java/org/jclouds/softlayer/handlers/SoftLayerErrorHandler.java
@@ -0,0 +1,91 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer.handlers;
+
+import java.io.IOException;
+
+import javax.annotation.Resource;
+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.logging.Logger;
+import org.jclouds.rest.AuthorizationException;
+import org.jclouds.rest.ResourceNotFoundException;
+import org.jclouds.util.Strings2;
+
+import com.google.common.base.Throwables;
+import com.google.common.io.Closeables;
+
+/**
+ * This will parse and set an appropriate exception on the command object.
+ *
+ * @author Adrian Cole
+ *
+ */
+@Singleton
+public class SoftLayerErrorHandler implements HttpErrorHandler {
+ @Resource
+ protected Logger logger = Logger.NULL;
+
+ public void handleError(HttpCommand command, HttpResponse response) {
+ // it is important to always read fully and close streams
+ String message = parseMessage(response);
+ Exception exception = message != null ? new HttpResponseException(command, response, message)
+ : new HttpResponseException(command, response);
+ try {
+ message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
+ response.getStatusLine());
+ switch (response.getStatusCode()) {
+ case 401:
+ case 403:
+ exception = new AuthorizationException(message, exception);
+ break;
+ case 404:
+ if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
+ exception = new ResourceNotFoundException(message, exception);
+ }
+ break;
+ }
+ } finally {
+ if (response.getPayload() != null)
+ Closeables.closeQuietly(response.getPayload().getInput());
+ command.setException(exception);
+ }
+ }
+
+ public String parseMessage(HttpResponse response) {
+ if (response.getPayload() == null)
+ return null;
+ try {
+ return Strings2.toStringAndClose(response.getPayload().getInput());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ try {
+ response.getPayload().getInput().close();
+ } catch (IOException e) {
+ Throwables.propagate(e);
+ }
+ }
+ }
+}
diff --git a/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerAsyncClientTest.java b/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerAsyncClientTest.java
new file mode 100644
index 0000000000..1146d84b02
--- /dev/null
+++ b/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerAsyncClientTest.java
@@ -0,0 +1,112 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer;
+
+import static org.jclouds.rest.RestContextFactory.contextSpec;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.filters.BasicAuthentication;
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.rest.RestClientTest;
+import org.jclouds.rest.RestContextSpec;
+import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+import com.google.inject.TypeLiteral;
+
+/**
+ * Tests annotation parsing of {@code SoftLayerAsyncClient}
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit")
+public class SoftLayerAsyncClientTest extends RestClientTest {
+
+ public void testListVirtualGuests() throws SecurityException, NoSuchMethodException, IOException {
+ Method method = SoftLayerAsyncClient.class.getMethod("listVirtualGuests");
+ HttpRequest httpRequest = processor.createRequest(method);
+
+ assertRequestLineEquals(httpRequest,
+ "GET https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.json HTTP/1.1");
+ assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
+ assertPayloadEquals(httpRequest, null, null, false);
+
+ // now make sure request filters apply by replaying
+ httpRequest = Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
+ httpRequest = Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
+
+ assertRequestLineEquals(httpRequest,
+ "GET https://api.softlayer.com/rest/v3/SoftLayer_Account/VirtualGuests.json HTTP/1.1");
+ // for example, using basic authentication, we should get "only one"
+ // header
+ assertNonPayloadHeadersEqual(httpRequest,
+ "Accept: application/json\nAuthorization: Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==\n");
+ assertPayloadEquals(httpRequest, null, null, false);
+
+ assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
+ assertSaxResponseParserClassEquals(method, null);
+ assertExceptionParserClassEquals(method, ReturnEmptySetOnNotFoundOr404.class);
+
+ checkFilters(httpRequest);
+
+ }
+
+ public void testGetVirtualGuest() throws SecurityException, NoSuchMethodException, IOException {
+ Method method = SoftLayerAsyncClient.class.getMethod("getVirtualGuest", long.class);
+ HttpRequest httpRequest = processor.createRequest(method, 1234);
+
+ assertRequestLineEquals(httpRequest,
+ "GET https://api.softlayer.com/rest/v3/SoftLayer_Virtual_Guest/1234.json HTTP/1.1");
+ assertNonPayloadHeadersEqual(httpRequest, "Accept: application/json\n");
+ assertPayloadEquals(httpRequest, null, null, false);
+
+ assertResponseParserClassEquals(method, httpRequest, ParseJson.class);
+ assertSaxResponseParserClassEquals(method, null);
+ assertExceptionParserClassEquals(method, ReturnNullOnNotFoundOr404.class);
+
+ checkFilters(httpRequest);
+
+ }
+
+ @Override
+ protected void checkFilters(HttpRequest request) {
+ assertEquals(request.getFilters().size(), 1);
+ assertEquals(request.getFilters().get(0).getClass(), BasicAuthentication.class);
+ }
+
+ @Override
+ protected TypeLiteral> createTypeLiteral() {
+ return new TypeLiteral>() {
+ };
+ }
+
+ @Override
+ public RestContextSpec createContextSpec() {
+ return contextSpec("softlayer", "https://api.softlayer.com/rest", "3", "", "identity", "credential",
+ SoftLayerClient.class, SoftLayerAsyncClient.class);
+ }
+}
diff --git a/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerClientLiveTest.java b/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerClientLiveTest.java
new file mode 100644
index 0000000000..93a09e5b02
--- /dev/null
+++ b/sandbox-providers/softlayer/src/test/java/org/jclouds/softlayer/SoftLayerClientLiveTest.java
@@ -0,0 +1,103 @@
+/**
+ *
+ * Copyright (C) 2011 Cloud Conscious, LLC.
+ *
+ * ====================================================================
+ * Licensed 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.softlayer;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Properties;
+import java.util.Set;
+
+import org.jclouds.logging.log4j.config.Log4JLoggingModule;
+import org.jclouds.rest.RestContext;
+import org.jclouds.rest.RestContextFactory;
+import org.jclouds.softlayer.domain.VirtualGuest;
+import org.testng.annotations.AfterGroups;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Module;
+
+/**
+ * Tests behavior of {@code SoftLayerClient}
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "live")
+public class SoftLayerClientLiveTest {
+
+ private SoftLayerClient client;
+ private RestContext context;
+
+ @BeforeGroups(groups = { "live" })
+ public void setupClient() {
+ String identity = checkNotNull(System.getProperty("test.softlayer.identity"), "test.softlayer.identity");
+ String credential = checkNotNull(System.getProperty("test.softlayer.credential"), "test.softlayer.credential");
+
+ Properties restProperties = new Properties();
+ restProperties.setProperty("softlayer.contextbuilder", SoftLayerContextBuilder.class.getName());
+ restProperties.setProperty("softlayer.propertiesbuilder", SoftLayerPropertiesBuilder.class.getName());
+
+ context = new RestContextFactory(restProperties).createContext("softlayer", identity, credential, ImmutableSet
+ . of(new Log4JLoggingModule()));
+
+ client = context.getApi();
+ }
+
+ @AfterGroups(groups = "live")
+ void tearDown() {
+ if (context != null)
+ context.close();
+ }
+
+ @Test
+ public void testListVirtualGuests() throws Exception {
+ Set response = client.listVirtualGuests();
+ assert null != response;
+ assertTrue(response.size() >= 0);
+ for (VirtualGuest vg : response) {
+ VirtualGuest newDetails = client.getVirtualGuest(vg.getId());
+ assertEquals(vg.getId(), newDetails.getId());
+ checkVirtualGuest(vg);
+ }
+ }
+
+ private void checkVirtualGuest(VirtualGuest vg) {
+ assert vg.getAccountId() > 0 : vg;
+ assert vg.getCreateDate() != null : vg;
+ assert vg.getDomain() != null : vg;
+ assert vg.getFullyQualifiedDomainName() != null : vg;
+ assert vg.getHostname() != null : vg;
+ assert vg.getId() > 0 : vg;
+ assert vg.getMaxCpu() > 0 : vg;
+ assert vg.getMaxCpuUnits() != null : vg;
+ assert vg.getMaxMemory() > 0 : vg;
+ assert vg.getMetricPollDate() != null : vg;
+ assert vg.getModifyDate() != null : vg;
+ assert vg.getStartCpus() > 0 : vg;
+ assert vg.getStatusId() >= 0 : vg;
+ assert vg.getUuid() != null : vg;
+ assert vg.getPrimaryBackendIpAddress() != null : vg;
+ assert vg.getPrimaryIpAddress() != null : vg;
+ }
+
+}
diff --git a/sandbox-providers/softlayer/src/test/resources/log4j.xml b/sandbox-providers/softlayer/src/test/resources/log4j.xml
new file mode 100644
index 0000000000..c75f2a3cdf
--- /dev/null
+++ b/sandbox-providers/softlayer/src/test/resources/log4j.xml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file