You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2014/10/05 19:50:19 UTC

[11/20] JCLOUDS-664 Updating Azure compute provider

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/features/HostedServiceApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/HostedServiceApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/HostedServiceApi.java
new file mode 100644
index 0000000..9e6b9a2
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/HostedServiceApi.java
@@ -0,0 +1,157 @@
+/*
+ * 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.azurecompute.features;
+
+import java.util.List;
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.azurecompute.binders.BindCreateHostedServiceToXmlPayload;
+import org.jclouds.azurecompute.domain.HostedService;
+import org.jclouds.azurecompute.domain.HostedServiceWithDetailedProperties;
+import org.jclouds.azurecompute.functions.ParseRequestIdHeader;
+import org.jclouds.azurecompute.options.CreateHostedServiceOptions;
+import org.jclouds.azurecompute.xml.HostedServiceHandler;
+import org.jclouds.azurecompute.xml.HostedServiceWithDetailedPropertiesHandler;
+import org.jclouds.azurecompute.xml.ListHostedServicesHandler;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.QueryParams;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.XMLResponseParser;
+
+import static org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+import static org.jclouds.Fallbacks.NullOnNotFoundOr404;
+
+/**
+ * The Service Management API includes operations for managing the hosted services beneath your
+ * subscription.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/ee460812">docs</a>
+ */
+@Path("/services/hostedservices")
+@Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Consumes(MediaType.APPLICATION_XML)
+public interface HostedServiceApi {
+
+   /**
+    * The List Hosted Services operation lists the hosted services available under the current
+    * subscription.
+    *
+    * @return the response object
+    */
+   @Named("ListHostedServices")
+   @GET
+   @XMLResponseParser(ListHostedServicesHandler.class)
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<HostedServiceWithDetailedProperties> list();
+
+   /**
+    * The Create Hosted Service operation creates a new hosted service in Windows Azure.
+    *
+    * @param name
+    *           A name for the hosted service that is unique within Windows Azure. This name is the
+    *           DNS prefix name and can be used to access the hosted service.
+    *
+    *           For example: http://name.cloudapp.net//
+    * @param label
+    *           The name can be used identify the storage account for your tracking purposes. The
+    *           name can be up to 100 characters in length.
+    * @param location
+    *           The location where the hosted service will be created.
+    * @return the requestId to track this async request progress
+    *
+    * @see <a href="http://msdn.microsoft.com/en-us/library/ee460812">docs</a>
+    */
+   @Named("CreateHostedService")
+   @POST
+   @MapBinder(BindCreateHostedServiceToXmlPayload.class)
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String createServiceWithLabelInLocation(@PayloadParam("name") String name,
+         @PayloadParam("label") String label, @PayloadParam("location") String location);
+
+   /**
+    * same as {@link #createServiceWithLabelInLocation(String, String, String)} , except you can
+    * specify optional parameters such as extended properties or a description.
+    *
+    * @param options
+    *           parameters such as extended properties or a description.
+    */
+   @Named("CreateHostedService")
+   @POST
+   @MapBinder(BindCreateHostedServiceToXmlPayload.class)
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String createServiceWithLabelInLocation(@PayloadParam("name") String name,
+         @PayloadParam("label") String label, @PayloadParam("location") String location,
+         @PayloadParam("options") CreateHostedServiceOptions options);
+
+   /**
+    * The Get Hosted Service Properties operation retrieves system properties for the specified
+    * hosted service. These properties include the service name and service type; the name of the
+    * affinity group to which the service belongs, or its location if it is not part of an affinity
+    * group.
+    *
+    * @param name
+    *           the unique DNS Prefix value in the Windows Azure Management Portal
+    */
+   @Named("GetHostedServiceProperties")
+   @GET
+   @Path("/{name}")
+   @XMLResponseParser(HostedServiceHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   HostedService get(@PathParam("name") String name);
+
+   /**
+    * like {@link #get(String)}, except additional data such as status and deployment information is
+    * returned.
+    *
+    * @param name
+    *           the unique DNS Prefix value in the Windows Azure Management Portal
+    */
+   @Named("GetHostedServiceProperties")
+   @GET
+   @Path("/{name}")
+   @QueryParams(keys = "embed-detail", values = "true")
+   @XMLResponseParser(HostedServiceWithDetailedPropertiesHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   HostedServiceWithDetailedProperties getDetails(@PathParam("name") String name);
+
+   /**
+    * The Delete Hosted Service operation deletes the specified hosted service from Windows Azure.
+    *
+    * @param name
+    *           the unique DNS Prefix value in the Windows Azure Management Portal
+    *
+    * @return request id or null, if not found
+    */
+   @Named("DeleteHostedService")
+   @DELETE
+   @Path("/{name}")
+   @Fallback(NullOnNotFoundOr404.class)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String delete(@PathParam("name") String name);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/features/ImageApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/ImageApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/ImageApi.java
new file mode 100644
index 0000000..cdf7029
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/ImageApi.java
@@ -0,0 +1,99 @@
+/*
+ * 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.azurecompute.features;
+
+import java.util.List;
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.azurecompute.binders.BindOSImageParamsToXmlPayload;
+import org.jclouds.azurecompute.domain.Image;
+import org.jclouds.azurecompute.domain.ImageParams;
+import org.jclouds.azurecompute.functions.ImageParamsName;
+import org.jclouds.azurecompute.functions.ParseRequestIdHeader;
+import org.jclouds.azurecompute.xml.ListImagesHandler;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.ParamParser;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.XMLResponseParser;
+
+import static org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+import static org.jclouds.Fallbacks.NullOnNotFoundOr404;
+
+/**
+ * The Service Management API includes operations for managing the OS images in your subscription.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/jj157175">docs</a>
+ */
+@Path("/services/images")
+@Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Consumes(MediaType.APPLICATION_XML)
+public interface ImageApi {
+
+   /**
+    * The List Hosted Services operation lists the hosted services available under the current
+    * subscription.
+    */
+   @Named("ListImages")
+   @GET
+   @XMLResponseParser(ListImagesHandler.class)
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<Image> list();
+
+   /**
+    * The Add OS Image operation adds an OS image that is currently stored in a storage account in your subscription to
+    * the image repository.
+    */
+   @Named("AddImage")
+   @POST
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String add(@BinderParam(BindOSImageParamsToXmlPayload.class) ImageParams params);
+
+   /**
+    * The Update OS Image operation updates an OS image that in your image repository.
+    */
+   @Named("UpdateImage")
+   @PUT
+   @Path("/{imageName}")
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String update(@PathParam("imageName") @ParamParser(ImageParamsName.class)
+               @BinderParam(BindOSImageParamsToXmlPayload.class) ImageParams params);
+
+   /**
+    * The Delete Hosted Service operation deletes the specified hosted service from Windows Azure.
+    *
+    * @param imageName
+    *           the unique DNS Prefix value in the Windows Azure Management Portal
+    */
+   @Named("DeleteImage")
+   @DELETE
+   @Path("/{imageName}")
+   @Fallback(NullOnNotFoundOr404.class)
+   @ResponseParser(ParseRequestIdHeader.class)
+   String delete(@PathParam("imageName") String imageName);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/features/LocationApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/LocationApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/LocationApi.java
new file mode 100644
index 0000000..1621139
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/LocationApi.java
@@ -0,0 +1,54 @@
+/*
+ * 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.azurecompute.features;
+
+import java.util.List;
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.azurecompute.domain.Location;
+import org.jclouds.azurecompute.xml.ListLocationsHandler;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.XMLResponseParser;
+
+import static org.jclouds.Fallbacks.EmptyListOnNotFoundOr404;
+
+/**
+ * The Service Management API includes operations for listing the available data center locations
+ * for a hosted service in your subscription.
+ * <p/>
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/gg441299" />
+ */
+@Path("/locations")
+@Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Consumes(MediaType.APPLICATION_XML)
+public interface LocationApi {
+
+   /**
+    * The List Locations operation lists all of the data center locations that are valid for your
+    * subscription.
+    */
+   @Named("ListLocations")
+   @GET
+   @XMLResponseParser(ListLocationsHandler.class)
+   @Fallback(EmptyListOnNotFoundOr404.class)
+   List<Location> list();
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/features/OperationApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/OperationApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/OperationApi.java
new file mode 100644
index 0000000..5ee97a6
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/OperationApi.java
@@ -0,0 +1,48 @@
+/*
+ * 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.azurecompute.features;
+
+import javax.inject.Named;
+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.azurecompute.domain.Operation;
+import org.jclouds.azurecompute.xml.OperationHandler;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.XMLResponseParser;
+
+import static org.jclouds.Fallbacks.NullOnNotFoundOr404;
+
+/**
+ * The Service Management API includes one operation for tracking the progress of asynchronous requests.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/ee460796">docs</a>
+ */
+@Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Consumes(MediaType.APPLICATION_XML)
+public interface OperationApi {
+
+   @Named("GetOperation")
+   @GET
+   @Path("/operations/{request-id}")
+   @XMLResponseParser(OperationHandler.class)
+   @Fallback(NullOnNotFoundOr404.class)
+   Operation get(@PathParam("request-id") String requestId);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java b/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java
new file mode 100644
index 0000000..5067029
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/features/VirtualMachineApi.java
@@ -0,0 +1,87 @@
+/*
+ * 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.azurecompute.features;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.jclouds.azurecompute.functions.ParseRequestIdHeader;
+import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.ResponseParser;
+
+/**
+ * The Service Management API includes operations for managing the virtual
+ * machines in your subscription.
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/jj157206">docs</a>
+ */
+@Path("/services/hostedservices/{serviceName}/deployments/{deploymentName}/roleinstances")
+@Headers(keys = "x-ms-version", values = "{jclouds.api-version}")
+@Consumes(MediaType.APPLICATION_XML)
+// NOTE: MS Docs refer to the commands as Role, but in the description, it is always Virtual Machine.
+public interface VirtualMachineApi {
+
+   @Named("RestartRole")
+   @POST
+   // Warning : the url in the documentation is WRONG ! @see
+   // http://social.msdn.microsoft.com/Forums/pl-PL/WAVirtualMachinesforWindows/thread/7ba2367b-e450-49e0-89e4-46c240e9d213
+   @Path("/{name}/Operations")
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   @Payload(value = "<RestartRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><OperationType>RestartRoleOperation</OperationType></RestartRoleOperation>")
+   String restart(@PathParam("name") String name);
+
+   /**
+    * http://msdn.microsoft.com/en-us/library/jj157201
+    */
+   @Named("CaptureRole")
+   @POST
+   @Path("/{name}/Operations")
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   @Payload(value = "<CaptureRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><OperationType>CaptureRoleOperation</OperationType><PostCaptureAction>Delete</PostCaptureAction><TargetImageLabel>{imageLabel}</TargetImageLabel><TargetImageName>{imageName}</TargetImageName></CaptureRoleOperation>")
+   String capture(@PathParam("name") String name, @PayloadParam("imageName") String imageName,
+         @PayloadParam("imageLabel") String imageLabel);
+
+   /**
+    * http://msdn.microsoft.com/en-us/library/jj157195
+    */
+   @Named("ShutdownRole")
+   @POST
+   @Path("/{name}/Operations")
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   @Payload(value = "<ShutdownRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><OperationType>ShutdownRoleOperation</OperationType></ShutdownRoleOperation>")
+   String shutdown(@PathParam("name") String name);
+
+   /**
+    * http://msdn.microsoft.com/en-us/library/jj157189
+    */
+   @Named("StartRole")
+   @POST
+   @Path("/{name}/Operations")
+   @Produces(MediaType.APPLICATION_XML)
+   @ResponseParser(ParseRequestIdHeader.class)
+   @Payload(value = "<StartRoleOperation xmlns=\"http://schemas.microsoft.com/windowsazure\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\"><OperationType>StartRoleOperation</OperationType></StartRoleOperation>")
+   String start(@PathParam("name") String name);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/functions/ImageParamsName.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/functions/ImageParamsName.java b/azurecompute/src/main/java/org/jclouds/azurecompute/functions/ImageParamsName.java
new file mode 100644
index 0000000..077b63c
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/functions/ImageParamsName.java
@@ -0,0 +1,34 @@
+/*
+ * 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.azurecompute.functions;
+
+import com.google.common.base.Function;
+import javax.inject.Singleton;
+import org.jclouds.azurecompute.domain.ImageParams;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+@Singleton
+public class ImageParamsName implements Function<Object, String> {
+   @Override
+   public String apply(Object input) {
+      checkArgument(checkNotNull(input, "input") instanceof ImageParams,
+               "this function is only valid for ImageParams!");
+      return checkNotNull(ImageParams.class.cast(input), "ImageParams").getName();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/functions/ParseRequestIdHeader.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/functions/ParseRequestIdHeader.java b/azurecompute/src/main/java/org/jclouds/azurecompute/functions/ParseRequestIdHeader.java
new file mode 100644
index 0000000..2a0d5aa
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/functions/ParseRequestIdHeader.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.azurecompute.functions;
+
+import com.google.common.base.Function;
+import javax.inject.Singleton;
+import org.jclouds.http.HttpResponse;
+
+import static org.jclouds.http.HttpUtils.releasePayload;
+
+/**
+ * Parses an x-ms-request-id the header
+ *
+ * A value that uniquely identifies a request made against the management service. For an
+ * asynchronous operation, you can call get operation status with the value of the header to
+ * determine whether the operation is complete, has failed, or is still in progress.
+ */
+@Singleton
+public class ParseRequestIdHeader implements Function<HttpResponse, String> {
+
+   public String apply(HttpResponse from) {
+      releasePayload(from);
+      String requestId = from.getFirstHeaderOrNull("x-ms-request-id");
+      if (requestId != null) {
+         return requestId;
+      }
+      throw new IllegalStateException("did not receive RequestId in: " + from);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/options/CreateHostedServiceOptions.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/options/CreateHostedServiceOptions.java b/azurecompute/src/main/java/org/jclouds/azurecompute/options/CreateHostedServiceOptions.java
new file mode 100644
index 0000000..18ab095
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/options/CreateHostedServiceOptions.java
@@ -0,0 +1,115 @@
+/*
+ * 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.azurecompute.options;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import java.util.Map;
+
+/**
+ * Optional parameters for creating a hosted service
+ *
+ * @see <a href="http://msdn.microsoft.com/en-us/library/gg441304" >docs</a>
+ */
+public class CreateHostedServiceOptions implements Cloneable {
+
+   private Optional<String> description = Optional.absent();
+   private Optional<Map<String, String>> extendedProperties = Optional.absent();
+
+   /**
+    * @see CreateHostedServiceOptions#getDescription()
+    */
+   public CreateHostedServiceOptions description(String description) {
+      this.description = Optional.fromNullable(description);
+      return this;
+   }
+
+   /**
+    * @see CreateHostedServiceOptions#getExtendedProperties()
+    */
+   public CreateHostedServiceOptions extendedProperties(Map<String, String> extendedProperties) {
+      this.extendedProperties = Optional.fromNullable(extendedProperties);
+      return this;
+   }
+
+   /**
+    * A description for the hosted service. The description can be up to 1024 characters in length.
+    */
+   public Optional<String> getDescription() {
+      return description;
+   }
+
+   /**
+    * Represents the name of an extended hosted service property. Each extended property must have
+    * both a defined name and value. You can have a maximum of 50 extended property name/value
+    * pairs.
+    *
+    * The maximum length of the Name element is 64 characters, only alphanumeric characters and
+    * underscores are valid in the Name, and the name must start with a letter. Each extended
+    * property value has a maximum length of 255 characters.
+    */
+   public Optional<Map<String, String>> getExtendedProperties() {
+      return extendedProperties;
+   }
+
+   public static class Builder {
+
+      /**
+       * @see CreateHostedServiceOptions#getDescription()
+       */
+      public static CreateHostedServiceOptions description(String description) {
+         return new CreateHostedServiceOptions().description(description);
+      }
+
+      /**
+       * @see CreateHostedServiceOptions#getExtendedProperties()
+       */
+      public static CreateHostedServiceOptions extendedProperties(Map<String, String> extendedProperties) {
+         return new CreateHostedServiceOptions().extendedProperties(extendedProperties);
+      }
+   }
+
+   @Override
+   public CreateHostedServiceOptions clone() {
+      return new CreateHostedServiceOptions().description(description.orNull()).extendedProperties(
+               extendedProperties.orNull());
+   }
+
+   @Override
+   public boolean equals(Object obj) {
+      if (this == obj)
+         return true;
+      if (obj == null)
+         return false;
+      if (getClass() != obj.getClass())
+         return false;
+      CreateHostedServiceOptions other = CreateHostedServiceOptions.class.cast(obj);
+      return Objects.equal(this.description, other.description)
+               && Objects.equal(this.extendedProperties, other.extendedProperties);
+   }
+
+   @Override
+   public int hashCode() {
+      return Objects.hashCode(description, extendedProperties);
+   }
+
+   @Override
+   public String toString() {
+      return Objects.toStringHelper("").omitNullValues().add("description", description.orNull())
+               .add("extendedProperties", extendedProperties.orNull()).toString();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/suppliers/KeyStoreSupplier.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/suppliers/KeyStoreSupplier.java b/azurecompute/src/main/java/org/jclouds/azurecompute/suppliers/KeyStoreSupplier.java
new file mode 100644
index 0000000..d4955e1
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/suppliers/KeyStoreSupplier.java
@@ -0,0 +1,129 @@
+/*
+ * 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.azurecompute.suppliers;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Supplier;
+import com.google.common.io.ByteSource;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Collection;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.jclouds.crypto.Crypto;
+import org.jclouds.crypto.Pems;
+import org.jclouds.domain.Credentials;
+import org.jclouds.location.Provider;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+
+/**
+ * TODO this code needs to be completely refactored. It needs to stop using KeyStore of at all possible and definitely
+ * the local filesystem. Please look at oauth for examples on how to do this via PEMs.
+ */
+@Deprecated
+@Singleton
+public class KeyStoreSupplier implements Supplier<KeyStore> {
+   private final Crypto crypto;
+   private final Supplier<Credentials> creds;
+
+   @Inject
+   KeyStoreSupplier(Crypto crypto, @Provider Supplier<Credentials> creds) {
+      this.crypto = crypto;
+      this.creds = creds;
+   }
+
+   @Override
+   public KeyStore get() {
+      Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
+      String cert = checkNotNull(currentCreds.identity, "credential supplier returned null identity (should be cert)");
+      String keyStorePassword = checkNotNull(currentCreds.credential,
+            "credential supplier returned null credential (should be keyStorePassword)");
+      try {
+         KeyStore keyStore = KeyStore.getInstance("PKCS12");
+
+         File certFile = new File(checkNotNull(cert));
+         if (certFile.isFile()) { // cert is path to pkcs12 file
+            FileInputStream stream = new FileInputStream(certFile);
+            try {
+               keyStore.load(stream, keyStorePassword.toCharArray());
+            } finally {
+               stream.close();
+            }
+         } else { // cert is PEM encoded, containing private key and certs
+
+            // split in private key and certs
+            int privateKeyBeginIdx = cert.indexOf("-----BEGIN PRIVATE KEY");
+            int privateKeyEndIdx = cert.indexOf("-----END PRIVATE KEY");
+            String pemPrivateKey = cert.substring(privateKeyBeginIdx, privateKeyEndIdx + 26);
+
+            StringBuilder pemCerts = new StringBuilder();
+            int certsBeginIdx = 0;
+
+            do {
+               certsBeginIdx = cert.indexOf("-----BEGIN CERTIFICATE", certsBeginIdx);
+
+               if (certsBeginIdx >= 0) {
+                  int certsEndIdx = cert.indexOf("-----END CERTIFICATE", certsBeginIdx) + 26;
+                  pemCerts.append(cert.substring(certsBeginIdx, certsEndIdx));
+                  certsBeginIdx = certsEndIdx;
+               }
+            } while (certsBeginIdx != -1);
+
+            // parse private key
+            KeySpec keySpec = Pems.privateKeySpec(ByteSource.wrap(pemPrivateKey.getBytes(Charsets.UTF_8)));
+            PrivateKey privateKey = crypto.rsaKeyFactory().generatePrivate(keySpec);
+
+            // populate keystore with private key and certs
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            @SuppressWarnings("unchecked")
+            Collection<Certificate> certs = (Collection<Certificate>) cf.generateCertificates(new ByteArrayInputStream(
+                  pemCerts.toString().getBytes(Charsets.UTF_8)));
+            keyStore.load(null);
+            keyStore.setKeyEntry("dummy", privateKey, keyStorePassword.toCharArray(),
+                  certs.toArray(new java.security.cert.Certificate[0]));
+
+         }
+         return keyStore;
+      } catch (NoSuchAlgorithmException e) {
+         throw propagate(e);
+      } catch (KeyStoreException e) {
+         throw propagate(e);
+      } catch (CertificateException e) {
+         throw propagate(e);
+      } catch (FileNotFoundException e) {
+         throw propagate(e);
+      } catch (IOException e) {
+         throw propagate(e);
+      } catch (InvalidKeySpecException e) {
+         throw propagate(e);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/suppliers/SSLContextWithKeysSupplier.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/suppliers/SSLContextWithKeysSupplier.java b/azurecompute/src/main/java/org/jclouds/azurecompute/suppliers/SSLContextWithKeysSupplier.java
new file mode 100644
index 0000000..1936bf8
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/suppliers/SSLContextWithKeysSupplier.java
@@ -0,0 +1,80 @@
+/*
+ * 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.azurecompute.suppliers;
+
+import com.google.common.base.Supplier;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpUtils;
+import org.jclouds.http.config.SSLModule.TrustAllCerts;
+import org.jclouds.location.Provider;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.propagate;
+
+/**
+ * TODO this code needs to be completely refactored. It needs to stop using KeyStore of at all possible and definitely
+ * the local filesystem. Please look at oauth for examples on how to do this via PEMs.
+ */
+@Deprecated
+@Singleton
+public class SSLContextWithKeysSupplier implements Supplier<SSLContext> {
+   private final Supplier<KeyStore> keyStore;
+   private final TrustManager[] trustManager;
+   private final Supplier<Credentials> creds;
+
+   @Inject
+   SSLContextWithKeysSupplier(Supplier<KeyStore> keyStore, @Provider Supplier<Credentials> creds, HttpUtils utils,
+         TrustAllCerts trustAllCerts) {
+      this.keyStore = keyStore;
+      this.trustManager = utils.trustAllCerts() ? new TrustManager[] { trustAllCerts } : null;
+      this.creds = creds;
+   }
+
+   @Override
+   public SSLContext get() {
+      Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
+      String keyStorePassword = checkNotNull(currentCreds.credential,
+            "credential supplier returned null credential (should be keyStorePassword)");
+      KeyManagerFactory kmf;
+      try {
+         kmf = KeyManagerFactory.getInstance("SunX509");
+         kmf.init(keyStore.get(), keyStorePassword.toCharArray());
+         SSLContext sc = SSLContext.getInstance("TLS");
+         sc.init(kmf.getKeyManagers(), trustManager, new SecureRandom());
+         return sc;
+      } catch (NoSuchAlgorithmException e) {
+         throw propagate(e);
+      } catch (UnrecoverableKeyException e) {
+         throw propagate(e);
+      } catch (KeyStoreException e) {
+         throw propagate(e);
+      } catch (KeyManagementException e) {
+         throw propagate(e);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/AttachmentHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/AttachmentHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/AttachmentHandler.java
new file mode 100644
index 0000000..5bde45e
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/AttachmentHandler.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import org.jclouds.azurecompute.domain.Disk.Attachment;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.util.SaxUtils;
+import org.xml.sax.SAXException;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/jj157176" >api</a>
+ */
+public class AttachmentHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Attachment> {
+
+   private StringBuilder currentText = new StringBuilder();
+   private Attachment.Builder builder = Attachment.builder();
+
+   @Override
+   public Attachment getResult() {
+      try {
+         return builder.build();
+      } finally {
+         builder = Attachment.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (qName.equals("HostedServiceName")) {
+         builder.hostedService(SaxUtils.currentOrNull(currentText));
+      } else if (qName.equals("DeploymentName")) {
+         builder.deployment(SaxUtils.currentOrNull(currentText));
+      } else if (qName.equals("RoleName")) {
+         builder.role(SaxUtils.currentOrNull(currentText));
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DeploymentHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DeploymentHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DeploymentHandler.java
new file mode 100644
index 0000000..8d92c72
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DeploymentHandler.java
@@ -0,0 +1,115 @@
+/*
+ * 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.azurecompute.xml;
+
+import com.google.common.collect.Lists;
+import java.net.URI;
+import java.util.List;
+import org.jclouds.azurecompute.domain.Deployment;
+import org.jclouds.azurecompute.domain.DeploymentSlot;
+import org.jclouds.azurecompute.domain.DeploymentStatus;
+import org.jclouds.azurecompute.domain.InstanceStatus;
+import org.jclouds.azurecompute.domain.RoleSize;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.io.BaseEncoding.base64;
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/ee460804" >api</a>
+ */
+public class DeploymentHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Deployment> {
+
+   private List<String> elements = Lists.newArrayList();
+   private StringBuilder currentText = new StringBuilder();
+   private Deployment.Builder builder = Deployment.builder();
+
+   @Override
+   public Deployment getResult() {
+      try {
+         return builder.build();
+      } finally {
+         builder = Deployment.builder();
+      }
+   }
+
+   @Override
+   public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+      elements.add(qName);
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (equalsOrSuffix(qName, "Name") && "Deployment".equals(elements.get(elements.size() - 2))) {
+         builder.deploymentName(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "DeploymentSlot")) {
+         final String dpltSlot = currentOrNull(currentText);
+         if (dpltSlot != null) {
+            builder.deploymentSlot(DeploymentSlot.fromValue(dpltSlot));
+         }
+      } else if (equalsOrSuffix(qName, "Status")) {
+         String deploymentStatus = currentOrNull(currentText);
+         if (deploymentStatus != null) {
+            builder.deploymentStatus(DeploymentStatus.fromValue(deploymentStatus));
+         }
+      } else if (equalsOrSuffix(qName, "Label")) {
+         String label = currentOrNull(currentText);
+         if (label != null) {
+            builder.deploymentLabel(new String(base64().decode(label), UTF_8));
+         }
+      } else if (equalsOrSuffix(qName, "Url")) {
+         final String url = currentOrNull(currentText);
+         if (url != null) {
+            builder.deploymentURL(URI.create(url));
+         }
+      } else if (equalsOrSuffix(qName, "RoleName")) {
+         builder.roleName(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "InstanceName")) {
+         builder.instanceName(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "InstanceStatus")) {
+         String instanceStatus = currentOrNull(currentText);
+         if (instanceStatus != null) {
+            builder.instanceStatus(InstanceStatus.fromValue(instanceStatus));
+         }
+      } else if (equalsOrSuffix(qName, "InstanceStateDetails")) {
+         builder.instanceStateDetails(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "InstanceErrorCode")) {
+         builder.instanceErrorCode(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "InstanceSize")) {
+         String instanceSize = currentOrNull(currentText);
+         if (instanceSize != null) {
+            builder.instanceSize(RoleSize.fromValue(instanceSize));
+         }
+      } else if (equalsOrSuffix(qName, "IpAddress")) {
+         builder.privateIpAddress(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "Vip")) {
+         builder.publicIpAddress(currentOrNull(currentText));
+      }
+
+      currentText.setLength(0);
+      elements.remove(elements.size() - 1);
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DetailedHostedServicePropertiesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DetailedHostedServicePropertiesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DetailedHostedServicePropertiesHandler.java
new file mode 100644
index 0000000..ad77ab4
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DetailedHostedServicePropertiesHandler.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import javax.inject.Inject;
+import org.jclouds.azurecompute.domain.DetailedHostedServiceProperties;
+import org.jclouds.azurecompute.domain.HostedService.Status;
+import org.jclouds.date.DateService;
+import org.xml.sax.SAXException;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/gg441293" >api</a>
+ */
+public class DetailedHostedServicePropertiesHandler extends HostedServicePropertiesHandler {
+
+   private final DateService dateService;
+
+   @Inject
+   private DetailedHostedServicePropertiesHandler(DateService dateService) {
+      this.dateService = dateService;
+   }
+
+   private DetailedHostedServiceProperties.Builder builder = DetailedHostedServiceProperties.builder();
+
+   private String name;
+
+   @Override
+   public DetailedHostedServiceProperties getResult() {
+      try {
+         return builder.fromHostedServiceProperties(super.getResult()).build();
+      } finally {
+         builder = DetailedHostedServiceProperties.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (equalsOrSuffix(qName, "DateCreated")) {
+         builder.created(dateService.iso8601SecondsDateParse(currentOrNull(currentText)));
+      } else if (equalsOrSuffix(qName, "DateLastModified")) {
+         builder.lastModified(dateService.iso8601SecondsDateParse(currentOrNull(currentText)));
+      } else if (equalsOrSuffix(qName, "Status")) {
+         String rawStatus = currentOrNull(currentText);
+         builder.rawStatus(rawStatus);
+         builder.status(Status.fromValue(rawStatus));
+      } else if (equalsOrSuffix(qName, "Name")) {
+         this.name = currentOrNull(currentText);
+      } else if (equalsOrSuffix(qName, "Value")) {
+         builder.addExtendedProperty(this.name, currentOrNull(currentText));
+         this.name = null;
+      } else {
+         super.endElement(uri, name, qName);
+      }
+      currentText = new StringBuilder();
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DiskHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DiskHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DiskHandler.java
new file mode 100644
index 0000000..3d933b2
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/DiskHandler.java
@@ -0,0 +1,107 @@
+/*
+ * 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.azurecompute.xml;
+
+import java.net.URI;
+import javax.inject.Inject;
+import org.jclouds.azurecompute.domain.Disk;
+import org.jclouds.azurecompute.domain.OSType;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/jj157176" >api</a>
+ */
+public class DiskHandler extends
+		ParseSax.HandlerForGeneratedRequestWithResult<Disk> {
+
+	private final AttachmentHandler attachmentHandler;
+
+	@Inject
+	private DiskHandler(AttachmentHandler attachmentHandler) {
+		this.attachmentHandler = attachmentHandler;
+	}
+
+	private StringBuilder currentText = new StringBuilder();
+	private Disk.Builder builder = Disk.builder();
+
+	private boolean inAttachment;
+
+	@Override
+	public Disk getResult() {
+		try {
+			return builder.build();
+		} finally {
+			builder = Disk.builder();
+		}
+	}
+
+	@Override
+	public void startElement(String uri, String localName, String qName,
+			Attributes attributes) throws SAXException {
+		if (equalsOrSuffix(qName, "AttachedTo")) {
+			inAttachment = true;
+		}
+	}
+
+	@Override
+	public void endElement(String uri, String name, String qName)
+			throws SAXException {
+		if (equalsOrSuffix(qName, "AttachedTo")) {
+			builder.attachedTo(attachmentHandler.getResult());
+			inAttachment = false;
+		} else if (inAttachment) {
+			attachmentHandler.endElement(uri, name, qName);
+		} else if (equalsOrSuffix(qName, "OS")) {
+			builder.os(OSType.fromValue(currentOrNull(currentText)));
+		} else if (equalsOrSuffix(qName, "Name")) {
+			builder.name(currentOrNull(currentText));
+		} else if (equalsOrSuffix(qName, "LogicalDiskSizeInGB")) {
+			String gb = currentOrNull(currentText);
+			if (gb != null)
+				builder.logicalSizeInGB(Integer.parseInt(gb));
+		} else if (equalsOrSuffix(qName, "Description")) {
+			builder.description(currentOrNull(currentText));
+		} else if (equalsOrSuffix(qName, "Location")) {
+			builder.location(currentOrNull(currentText));
+		} else if (equalsOrSuffix(qName, "AffinityGroup")) {
+			builder.affinityGroup(currentOrNull(currentText));
+		} else if (equalsOrSuffix(qName, "MediaLink")) {
+			String link = currentOrNull(currentText);
+			if (link != null)
+				builder.mediaLink(URI.create(link));
+		} else if (equalsOrSuffix(qName, "SourceImageName")) {
+			builder.sourceImage(currentOrNull(currentText));
+		} else if (equalsOrSuffix(qName, "Label")) {
+			builder.label(currentOrNull(currentText));
+		}
+		currentText = new StringBuilder();
+	}
+
+	@Override
+	public void characters(char ch[], int start, int length) {
+		if (inAttachment) {
+			attachmentHandler.characters(ch, start, length);
+		} else {
+			currentText.append(ch, start, length);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ErrorHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ErrorHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ErrorHandler.java
new file mode 100644
index 0000000..04dca23
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ErrorHandler.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import org.jclouds.azurecompute.domain.Error;
+import org.jclouds.azurecompute.domain.Error.Code;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.util.SaxUtils;
+import org.xml.sax.SAXException;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/ee460801" >api</a>
+ */
+public class ErrorHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Error> {
+
+   private StringBuilder currentText = new StringBuilder();
+   private Error.Builder builder = Error.builder();
+
+   @Override
+   public Error getResult() {
+      try {
+         return builder.build();
+      } finally {
+         builder = Error.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (qName.equals("Code")) {
+         String rawCode = SaxUtils.currentOrNull(currentText);
+         builder.rawCode(rawCode);
+         builder.code(Code.fromValue(rawCode));
+      } else if (qName.equals("Message")) {
+         builder.message(SaxUtils.currentOrNull(currentText));
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServiceHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServiceHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServiceHandler.java
new file mode 100644
index 0000000..04f009a
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServiceHandler.java
@@ -0,0 +1,93 @@
+/*
+ * 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.azurecompute.xml;
+
+import java.net.URI;
+import javax.inject.Inject;
+import org.jclouds.azurecompute.domain.HostedService;
+import org.jclouds.azurecompute.domain.HostedService.Builder;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/gg441293" >api</a>
+ */
+public class HostedServiceHandler extends ParseSax.HandlerForGeneratedRequestWithResult<HostedService> {
+
+   private final HostedServicePropertiesHandler hostedServicePropertiesHandler;
+
+   @Inject protected HostedServiceHandler(HostedServicePropertiesHandler hostedServicePropertiesHandler) {
+      this.hostedServicePropertiesHandler = hostedServicePropertiesHandler;
+   }
+
+   private StringBuilder currentText = new StringBuilder();
+   protected HostedService.Builder<?> builder = builder();
+
+   protected Builder<?> builder() {
+      return HostedService.builder();
+   }
+
+   private boolean inHostedServiceProperties;
+
+   @Override
+   public HostedService getResult() {
+      try {
+         return builder.build();
+      } finally {
+         builder = builder();
+      }
+   }
+
+   @Override
+   public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+      if (equalsOrSuffix(qName, "HostedServiceProperties")) {
+         inHostedServiceProperties = true;
+      }
+      if (inHostedServiceProperties) {
+         hostedServicePropertiesHandler.startElement(url, name, qName, attributes);
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+
+      if (equalsOrSuffix(qName, "HostedServiceProperties")) {
+         builder.properties(hostedServicePropertiesHandler.getResult());
+         inHostedServiceProperties = false;
+      } else if (inHostedServiceProperties) {
+         hostedServicePropertiesHandler.endElement(uri, name, qName);
+      } else if (equalsOrSuffix(qName, "Url")) {
+         builder.url(URI.create(currentOrNull(currentText)));
+      } else if (equalsOrSuffix(qName, "ServiceName")) {
+         builder.name(currentOrNull(currentText));
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      if (inHostedServiceProperties) {
+         hostedServicePropertiesHandler.characters(ch, start, length);
+      } else {
+         currentText.append(ch, start, length);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServicePropertiesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServicePropertiesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServicePropertiesHandler.java
new file mode 100644
index 0000000..d3962c5
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServicePropertiesHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.azurecompute.xml;
+
+import org.jclouds.azurecompute.domain.HostedServiceProperties;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.SAXException;
+
+import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.io.BaseEncoding.base64;
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/gg441293" >api</a>
+ */
+public class HostedServicePropertiesHandler extends
+         ParseSax.HandlerForGeneratedRequestWithResult<HostedServiceProperties> {
+
+   protected StringBuilder currentText = new StringBuilder();
+   private HostedServiceProperties.Builder<?> builder = HostedServiceProperties.builder();
+
+   @Override
+   public HostedServiceProperties getResult() {
+      try {
+         return builder.build();
+      } finally {
+         builder = HostedServiceProperties.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (equalsOrSuffix(qName, "Description")) {
+         builder.description(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "Location")) {
+         builder.location(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "AffinityGroup")) {
+         builder.affinityGroup(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "Label")) {
+         builder.label(new String(base64().decode(currentOrNull(currentText)), UTF_8));
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServiceWithDetailedPropertiesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServiceWithDetailedPropertiesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServiceWithDetailedPropertiesHandler.java
new file mode 100644
index 0000000..69193b1
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/HostedServiceWithDetailedPropertiesHandler.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import javax.inject.Inject;
+import org.jclouds.azurecompute.domain.HostedServiceWithDetailedProperties;
+
+public class HostedServiceWithDetailedPropertiesHandler extends HostedServiceHandler {
+
+   @Inject protected HostedServiceWithDetailedPropertiesHandler(
+            DetailedHostedServicePropertiesHandler hostedServicePropertiesHandler) {
+      super(hostedServicePropertiesHandler);
+   }
+
+   @Override
+   protected HostedServiceWithDetailedProperties.Builder builder() {
+      return HostedServiceWithDetailedProperties.builder();
+   }
+
+   @Override
+   public HostedServiceWithDetailedProperties getResult() {
+      try {
+         return HostedServiceWithDetailedProperties.class.cast(builder.build());
+      } finally {
+         builder = builder();
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ImageHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ImageHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ImageHandler.java
new file mode 100644
index 0000000..1182c64
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ImageHandler.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import java.net.URI;
+import org.jclouds.azurecompute.domain.Image;
+import org.jclouds.azurecompute.domain.OSType;
+import org.jclouds.http.functions.ParseSax;
+import org.xml.sax.SAXException;
+
+import static org.jclouds.util.SaxUtils.currentOrNull;
+import static org.jclouds.util.SaxUtils.equalsOrSuffix;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/jj157191" >api</a>
+ */
+public class ImageHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Image> {
+
+   private StringBuilder currentText = new StringBuilder();
+   private Image.Builder builder = Image.builder();
+
+   @Override
+   public Image getResult() {
+      try {
+         return builder.build();
+      } finally {
+         builder = Image.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (equalsOrSuffix(qName, "OS")) {
+         builder.os(OSType.fromValue(currentOrNull(currentText)));
+      } else if (equalsOrSuffix(qName, "Name")) {
+         builder.name(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "LogicalSizeInGB")) {
+         String gb = currentOrNull(currentText);
+         if (gb != null)
+            builder.logicalSizeInGB(Integer.parseInt(gb));
+      } else if (equalsOrSuffix(qName, "Description")) {
+         builder.description(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "Category")) {
+         builder.category(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "Location")) {
+         builder.location(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "AffinityGroup")) {
+         builder.affinityGroup(currentOrNull(currentText));
+      } else if (equalsOrSuffix(qName, "MediaLink")) {
+         String link = currentOrNull(currentText);
+         if (link != null)
+            builder.mediaLink(URI.create(link));
+      } else if (equalsOrSuffix(qName, "Eula")) {
+         String eulaField = currentOrNull(currentText);
+         if (eulaField != null) {
+            for (String eula : Splitter.on(';').split(eulaField)) {
+               if ((eula = Strings.emptyToNull(eula.trim())) != null) { // Dirty data in RightScale eula field.
+                  builder.eula(eula);
+               }
+            }
+         }
+      } else if (equalsOrSuffix(qName, "Label")) {
+         builder.label(currentOrNull(currentText));
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListDisksHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListDisksHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListDisksHandler.java
new file mode 100644
index 0000000..fb6ea13
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListDisksHandler.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.inject.Inject;
+import java.util.List;
+import org.jclouds.azurecompute.domain.Disk;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.util.SaxUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class ListDisksHandler extends ParseSax.HandlerForGeneratedRequestWithResult<List<Disk>> {
+
+   private final DiskHandler diskHandler;
+
+   private Builder<Disk> disks = ImmutableList.<Disk> builder();
+
+   private boolean inDisk;
+
+   @Inject
+   public ListDisksHandler(final DiskHandler diskHandler) {
+      this.diskHandler = diskHandler;
+   }
+
+   @Override
+   public List<Disk> getResult() {
+      return disks.build();
+   }
+
+   @Override
+   public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+      if (SaxUtils.equalsOrSuffix(qName, "Disk")) {
+         inDisk = true;
+      }
+      if (inDisk) {
+         diskHandler.startElement(url, name, qName, attributes);
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (qName.equals("Disk")) {
+         inDisk = false;
+         disks.add(diskHandler.getResult());
+      } else if (inDisk) {
+         diskHandler.endElement(uri, name, qName);
+      }
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      if (inDisk) {
+         diskHandler.characters(ch, start, length);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListHostedServicesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListHostedServicesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListHostedServicesHandler.java
new file mode 100644
index 0000000..875e787
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListHostedServicesHandler.java
@@ -0,0 +1,78 @@
+/*
+ * 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.azurecompute.xml;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.inject.Inject;
+import java.util.List;
+import org.jclouds.azurecompute.domain.HostedServiceWithDetailedProperties;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.util.SaxUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/ee460781">doc</a>
+ */
+public class ListHostedServicesHandler extends
+         ParseSax.HandlerForGeneratedRequestWithResult<List<HostedServiceWithDetailedProperties>> {
+
+   private final HostedServiceWithDetailedPropertiesHandler hostedServiceHandler;
+
+   private Builder<HostedServiceWithDetailedProperties> hostedServices = ImmutableList
+            .<HostedServiceWithDetailedProperties> builder();
+
+   private boolean inHostedService;
+
+   @Inject
+   public ListHostedServicesHandler(HostedServiceWithDetailedPropertiesHandler hostedServiceHandler) {
+      this.hostedServiceHandler = hostedServiceHandler;
+   }
+
+   @Override
+   public List<HostedServiceWithDetailedProperties> getResult() {
+      return hostedServices.build();
+   }
+
+   @Override
+   public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+      if (SaxUtils.equalsOrSuffix(qName, "HostedService")) {
+         inHostedService = true;
+      }
+      if (inHostedService) {
+         hostedServiceHandler.startElement(url, name, qName, attributes);
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (qName.equals("HostedService")) {
+         inHostedService = false;
+         hostedServices.add(hostedServiceHandler.getResult());
+      } else if (inHostedService) {
+         hostedServiceHandler.endElement(uri, name, qName);
+      }
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      if (inHostedService) {
+         hostedServiceHandler.characters(ch, start, length);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListImagesHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListImagesHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListImagesHandler.java
new file mode 100644
index 0000000..beae350
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListImagesHandler.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.inject.Inject;
+import java.util.List;
+import org.jclouds.azurecompute.domain.Image;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.util.SaxUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class ListImagesHandler extends ParseSax.HandlerForGeneratedRequestWithResult<List<Image>> {
+
+   private final ImageHandler locationHandler;
+
+   private Builder<Image> locations = ImmutableList.<Image> builder();
+
+   private boolean inOSImage;
+
+   @Inject
+   public ListImagesHandler(ImageHandler locationHandler) {
+      this.locationHandler = locationHandler;
+   }
+
+   @Override
+   public List<Image> getResult() {
+      return locations.build();
+   }
+
+   @Override
+   public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+      if (SaxUtils.equalsOrSuffix(qName, "OSImage")) {
+         inOSImage = true;
+      }
+      if (inOSImage) {
+         locationHandler.startElement(url, name, qName, attributes);
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (qName.equals("OSImage")) {
+         inOSImage = false;
+         locations.add(locationHandler.getResult());
+      } else if (inOSImage) {
+         locationHandler.endElement(uri, name, qName);
+      }
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      if (inOSImage) {
+         locationHandler.characters(ch, start, length);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListLocationsHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListLocationsHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListLocationsHandler.java
new file mode 100644
index 0000000..f257a6a
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/ListLocationsHandler.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.azurecompute.xml;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.inject.Inject;
+import java.util.List;
+import org.jclouds.azurecompute.domain.Location;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.util.SaxUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class ListLocationsHandler extends ParseSax.HandlerForGeneratedRequestWithResult<List<Location>> {
+
+   private final LocationHandler locationHandler;
+
+   private Builder<Location> locations = ImmutableList.<Location> builder();
+
+   private boolean inLocation;
+
+   @Inject
+   public ListLocationsHandler(LocationHandler locationHandler) {
+      this.locationHandler = locationHandler;
+   }
+
+   @Override
+   public List<Location> getResult() {
+      return locations.build();
+   }
+
+   @Override
+   public void startElement(String url, String name, String qName, Attributes attributes) throws SAXException {
+      if (SaxUtils.equalsOrSuffix(qName, "Location")) {
+         inLocation = true;
+      }
+      if (inLocation) {
+         locationHandler.startElement(url, name, qName, attributes);
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (qName.equals("Location")) {
+         inLocation = false;
+         locations.add(locationHandler.getResult());
+      } else if (inLocation) {
+         locationHandler.endElement(uri, name, qName);
+      }
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      if (inLocation) {
+         locationHandler.characters(ch, start, length);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs/blob/45ef2a18/azurecompute/src/main/java/org/jclouds/azurecompute/xml/LocationHandler.java
----------------------------------------------------------------------
diff --git a/azurecompute/src/main/java/org/jclouds/azurecompute/xml/LocationHandler.java b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/LocationHandler.java
new file mode 100644
index 0000000..d2e229a
--- /dev/null
+++ b/azurecompute/src/main/java/org/jclouds/azurecompute/xml/LocationHandler.java
@@ -0,0 +1,57 @@
+/*
+ * 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.azurecompute.xml;
+
+import org.jclouds.azurecompute.domain.Location;
+import org.jclouds.http.functions.ParseSax;
+import org.jclouds.util.SaxUtils;
+import org.xml.sax.SAXException;
+
+/**
+ * @see <a href="http://msdn.microsoft.com/en-us/library/gg441293" >api</a>
+ */
+public class LocationHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Location> {
+
+   private StringBuilder currentText = new StringBuilder();
+   private Location.Builder builder = Location.builder();
+
+   @Override
+   public Location getResult() {
+      try {
+         return builder.build();
+      } finally {
+         builder = Location.builder();
+      }
+   }
+
+   @Override
+   public void endElement(String uri, String name, String qName) throws SAXException {
+      if (qName.equals("Name")) {
+         builder.name(SaxUtils.currentOrNull(currentText));
+      } else if (qName.equals("DisplayName")) {
+         builder.displayName(SaxUtils.currentOrNull(currentText));
+      } else if (qName.equals("AvailableService")) {
+         builder.addAvailableService(SaxUtils.currentOrNull(currentText));
+      }
+      currentText = new StringBuilder();
+   }
+
+   @Override
+   public void characters(char ch[], int start, int length) {
+      currentText.append(ch, start, length);
+   }
+}