You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by za...@apache.org on 2015/03/11 20:53:03 UTC

[2/2] jclouds-labs-openstack git commit: JCLOUDS-806: Support OpenStack Poppy Service API

JCLOUDS-806: Support OpenStack Poppy Service API


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

Branch: refs/heads/master
Commit: 3b6094560318aaf940fadbc4255239d23369af23
Parents: eeceb98
Author: Jeremy Daggett <je...@rackspace.com>
Authored: Fri Feb 6 11:49:11 2015 -0800
Committer: Zack Shoylev <za...@rackspace.com>
Committed: Wed Mar 11 14:52:44 2015 -0500

----------------------------------------------------------------------
 openstack-poppy/pom.xml                         |  11 +
 .../jclouds/openstack/poppy/v1/PoppyApi.java    |   8 +-
 .../openstack/poppy/v1/PoppyApiMetadata.java    |   2 +
 .../openstack/poppy/v1/PoppyFallbacks.java      |  39 ---
 .../openstack/poppy/v1/domain/Caching.java      | 124 ++++++++
 .../openstack/poppy/v1/domain/CachingRule.java  |  99 +++++++
 .../poppy/v1/domain/CreateService.java          | 194 +++++++++++++
 .../openstack/poppy/v1/domain/Domain.java       |  99 +++++++
 .../openstack/poppy/v1/domain/Error.java        |  39 +++
 .../openstack/poppy/v1/domain/Flavor.java       |  22 +-
 .../openstack/poppy/v1/domain/Origin.java       | 143 ++++++++++
 .../openstack/poppy/v1/domain/Protocol.java     |  59 ++++
 .../openstack/poppy/v1/domain/Provider.java     |  16 +-
 .../openstack/poppy/v1/domain/Restriction.java  | 101 +++++++
 .../poppy/v1/domain/RestrictionRule.java        |  99 +++++++
 .../openstack/poppy/v1/domain/Service.java      | 115 ++++++++
 .../poppy/v1/domain/ServiceStatus.java          |  75 +++++
 .../openstack/poppy/v1/domain/Services.java     |  36 +++
 .../poppy/v1/domain/UpdateService.java          | 193 +++++++++++++
 .../poppy/v1/fallbacks/PoppyFallbacks.java      |  36 +++
 .../openstack/poppy/v1/features/FlavorApi.java  |  16 +-
 .../openstack/poppy/v1/features/ServiceApi.java | 147 ++++++++++
 .../functions/ParseServiceURIFromHeaders.java   |  43 +++
 .../poppy/v1/functions/ParseServices.java       |  38 +++
 .../v1/functions/ServicesToPagedIterable.java   |  64 +++++
 .../poppy/v1/mapbinders/JSONPatchUpdate.java    |  80 ++++++
 .../poppy/v1/features/FlavorApiLiveTest.java    |   1 -
 .../poppy/v1/features/ServiceApiLiveTest.java   |  90 ++++++
 .../poppy/v1/features/ServiceApiMockTest.java   | 285 +++++++++++++++++++
 .../resources/poppy_service_create_request.json |  36 +++
 .../resources/poppy_service_get_response.json   |  72 +++++
 .../resources/poppy_service_list_response.json  | 132 +++++++++
 .../poppy_service_list_response_paged1.json     | 135 +++++++++
 .../poppy_service_list_response_paged2.json     | 131 +++++++++
 .../resources/poppy_service_patch_response.json |   7 +
 .../cdn/uk/CDNUKFlavorApiLiveTest.java          |  27 ++
 .../cdn/uk/CDNUKServiceApiLiveTest.java         |  27 ++
 .../cdn/us/CDNUSFlavorApiLiveTest.java          |  27 ++
 .../cdn/us/CDNUSServiceApiLiveTest.java         |  27 ++
 39 files changed, 2840 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/pom.xml
----------------------------------------------------------------------
diff --git a/openstack-poppy/pom.xml b/openstack-poppy/pom.xml
index 6eca54d..02af2b9 100644
--- a/openstack-poppy/pom.xml
+++ b/openstack-poppy/pom.xml
@@ -90,8 +90,19 @@
     <dependency>
       <groupId>com.google.auto.value</groupId>
       <artifactId>auto-value</artifactId>
+      <version>1.0</version>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.jclouds.driver</groupId>
+      <artifactId>jclouds-okhttp</artifactId>
+      <version>${project.parent.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.github.fge</groupId>
+      <artifactId>json-patch</artifactId>
+      <version>1.9</version>
+    </dependency>
   </dependencies>
 
   <profiles>

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApi.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApi.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApi.java
index ac56f15..6f011f5 100644
--- a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApi.java
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApi.java
@@ -25,9 +25,10 @@ import javax.ws.rs.Path;
 import javax.ws.rs.core.MediaType;
 
 import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
-import org.jclouds.openstack.poppy.v1.PoppyFallbacks.FalseOn500or503;
 import org.jclouds.openstack.poppy.v1.config.CDN;
+import org.jclouds.openstack.poppy.v1.fallbacks.PoppyFallbacks.FalseOn500or503;
 import org.jclouds.openstack.poppy.v1.features.FlavorApi;
+import org.jclouds.openstack.poppy.v1.features.ServiceApi;
 import org.jclouds.rest.annotations.Delegate;
 import org.jclouds.rest.annotations.Endpoint;
 import org.jclouds.rest.annotations.Fallback;
@@ -62,4 +63,9 @@ public interface PoppyApi extends Closeable {
    @Delegate
    FlavorApi getFlavorApi();
 
+   /**
+    * Provides access to Service features.
+    */
+   @Delegate
+   ServiceApi getServiceApi();
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApiMetadata.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApiMetadata.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApiMetadata.java
index 470b41d..b5e9a44 100644
--- a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApiMetadata.java
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyApiMetadata.java
@@ -23,6 +23,7 @@ import java.net.URI;
 import java.util.Properties;
 
 import org.jclouds.apis.ApiMetadata;
+import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule;
 import org.jclouds.openstack.keystone.v2_0.config.AuthenticationApiModule;
 import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
 import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
@@ -75,6 +76,7 @@ public class PoppyApiMetadata extends BaseHttpApiMetadata<PoppyApi> {
          .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
                            .add(AuthenticationApiModule.class)
                            .add(KeystoneAuthenticationModule.class)
+                           .add(OkHttpCommandExecutorServiceModule.class)
                            .add(ProviderModule.class)
                            .add(PoppyHttpApiModule.class).build());
       }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyFallbacks.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyFallbacks.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyFallbacks.java
deleted file mode 100644
index dc2872f..0000000
--- a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/PoppyFallbacks.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.openstack.poppy.v1;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Predicates.in;
-import static com.google.common.base.Throwables.propagate;
-import static com.google.common.primitives.Ints.asList;
-import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
-
-import org.jclouds.Fallback;
-
-public final class PoppyFallbacks {
-   private PoppyFallbacks() {
-   }
-
-   public static class FalseOn500or503 implements Fallback<Boolean> {
-      @Override
-      public Boolean createOrPropagate(Throwable t) throws Exception {
-         if (returnValueOnCodeOrNull(checkNotNull(t, "throwable"), false, in(asList(500, 503))) != null)
-            return false;
-         throw propagate(t);
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Caching.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Caching.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Caching.java
new file mode 100644
index 0000000..959825e
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Caching.java
@@ -0,0 +1,124 @@
+/*
+ * 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.openstack.poppy.v1.domain;
+
+import java.util.List;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Representation of an OpenStack Poppy Caching Rule.
+ */
+@AutoValue
+public abstract class Caching {
+   /**
+    * @see Builder#name(String)
+    */
+   public abstract String getName();
+
+   /**
+    * @see Builder#ttl(int)
+    */
+   public abstract int getTtl();
+
+   /**
+    * @see Builder#rules(List)
+    */
+   @Nullable public abstract List<CachingRule> getRules();
+
+   @SerializedNames({ "name", "ttl", "rules" })
+   static Caching create(String name, int ttl, List<CachingRule> rules) {
+      return builder().name(name).ttl(ttl).rules(rules).build();
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+   public Builder toBuilder() {
+      return builder()
+            .name(getName())
+            .ttl(getTtl())
+            .rules(getRules());
+   }
+
+   public static final class Builder {
+      private String name;
+      private Integer ttl;
+      private List<CachingRule> rules;
+      Builder() {
+      }
+      Builder(Caching source) {
+         name(source.getName());
+         ttl(source.getTtl());
+         rules(source.getRules());
+      }
+
+      /**
+       * Required.
+       * @param name Specifies the name of this caching rule. The minimum length for name is 1. The maximum length is
+       *             256. Note: default is a reserved name used for the default TTL setting.
+       * @return The Caching builder.
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param ttl Specifies the TTL to apply. The value of ttl must be greater than or equal to 0.
+       * @return The Caching builder.
+       */
+      public Builder ttl(int ttl) {
+         this.ttl = ttl;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param rules Specifies a collection of rules that determine if this TTL should be applied to an asset.
+       *              Note: This is a required property if more than one entry is present for caching.
+       * @return The Caching builder.
+       */
+      public Builder rules(List<CachingRule> rules) {
+         this.rules = rules;
+         return this;
+      }
+
+      public Caching build() {
+         String missing = "";
+         if (name == null) {
+            missing += " name";
+         }
+         if (ttl == null) {
+            missing += " ttl";
+         }
+         if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+         }
+         Caching result = new AutoValue_Caching(
+               this.name,
+               this.ttl,
+               rules != null ? ImmutableList.copyOf(this.rules) : null);
+         return result;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/CachingRule.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/CachingRule.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/CachingRule.java
new file mode 100644
index 0000000..f43c7f0
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/CachingRule.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.openstack.poppy.v1.domain;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class CachingRule {
+   /**
+    * @see Builder#name(String)
+    */
+   public abstract String getName();
+
+   /**
+    * @see Builder#requestURL(String)
+    */
+   public abstract String getRequestURL();
+
+   @SerializedNames({ "name", "request_url" })
+   private static CachingRule create(String name, String requestUrl) {
+      return builder().name(name).requestURL(requestUrl).build();
+   }
+
+   public static Builder builder() {
+      return new Builder();
+   }
+
+   public Builder toBuilder() {
+      return builder()
+            .name(getName())
+            .requestURL(getRequestURL());
+   }
+
+   public static final class Builder {
+      private String name;
+      private String requestURL;
+      Builder() {
+      }
+      Builder(CachingRule source) {
+         name(source.getName());
+         requestURL(source.getRequestURL());
+      }
+
+      /**
+       * Required.
+       * @param name Specifies the name of this rule. The minimum length for name is 1. The maximum length is 256.
+       * @return The CachingRule builder.
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param requestURL Specifies the request URL that this rule should match for this TTL to be used.
+       *                   The minimum length for request_url is 1. The maximum length is 1024. (Regex is supported.)
+       * @return The CachingRule builder.
+       */
+      public Builder requestURL(String requestURL) {
+         this.requestURL = requestURL;
+         return this;
+      }
+
+      public CachingRule build() {
+         String missing = "";
+         if (name == null) {
+            missing += " name";
+         }
+         if (requestURL == null) {
+            missing += " requestURL";
+         }
+         if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+         }
+         CachingRule result = new AutoValue_CachingRule(
+               this.name,
+               this.requestURL);
+         return result;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/CreateService.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/CreateService.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/CreateService.java
new file mode 100644
index 0000000..98781a1
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/CreateService.java
@@ -0,0 +1,194 @@
+/*
+ * 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.openstack.poppy.v1.domain;
+
+import java.util.List;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Representation of creation options for an OpenStack Poppy Service.
+ */
+@AutoValue
+public abstract class CreateService {
+   /**
+    * @see Builder#name(String)
+    */
+   public abstract String getName();
+
+   /**
+    * @see Builder#domains(List)
+    */
+   public abstract List<Domain> getDomains();
+
+   /**
+    * @see Builder#origins(List)
+    */
+   public abstract List<Origin> getOrigins();
+
+   /**
+    * @see Builder#caching(List)
+    */
+   @Nullable public abstract List<Caching> getCaching();
+
+   /**
+    * @see Builder#restrictions(List)
+    */
+   @Nullable public abstract List<Restriction> getRestrictions();
+
+   /**
+    * @see Builder#flavorId(String)
+    */
+   public abstract String getFlavorId();
+
+   public static Builder builder() {
+      return new AutoValue_CreateService.Builder().caching(null).restrictions(null);
+   }
+   public Builder toBuilder() {
+      return builder()
+            .name(getName())
+            .domains(getDomains())
+            .origins(getOrigins())
+            .caching(getCaching())
+            .restrictions(getRestrictions())
+            .flavorId(getFlavorId());
+   }
+
+   @SerializedNames({ "name", "domains", "origins", "caching", "restrictions", "flavor_id" })
+   private static CreateService create(String name, List<Domain> domains, List<Origin> origins, List<Caching> caching,
+         List<Restriction> restrictions, String flavorId) {
+      return builder()
+            .name(name)
+            .domains(domains)
+            .origins(origins)
+            .caching(caching)
+            .restrictions(restrictions)
+            .flavorId(flavorId).build();
+   }
+
+   public static final class Builder {
+      private String name;
+      private List<Domain> domains;
+      private List<Origin> origins;
+      private List<Caching> caching;
+      private List<Restriction> restrictions;
+      private String flavorId;
+      Builder() {
+      }
+      Builder(CreateService source) {
+         name(source.getName());
+         domains(source.getDomains());
+         origins(source.getOrigins());
+         caching(source.getCaching());
+         restrictions(source.getRestrictions());
+         flavorId(source.getFlavorId());
+      }
+
+      /**
+       * Required.
+       * @param name Specifies the name of the service. The minimum length for name is 3. The maximum length is 256.
+       * @return The CreateService builder.
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param domains Specifies a list of domains used by users to access their website.
+       * @return The CreateService builder.
+       */
+      public Builder domains(List<Domain> domains) {
+         this.domains = domains;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param origins Specifies a list of origin domains or IP addresses where the original assets are stored.
+       * @return The CreateService builder.
+       */
+      public Builder origins(List<Origin> origins) {
+         this.origins = origins;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param caching Specifies the TTL rules for the assets under this service.
+       *                Supports wildcards for fine-grained control.
+       * @return The CreateService builder.
+       */
+      public Builder caching(List<Caching> caching) {
+         this.caching = caching;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param restrictions Specifies the restrictions that define who can access assets (content from the CDN cache).
+       * @return The CreateService builder.
+       */
+      public Builder restrictions(List<Restriction> restrictions) {
+         this.restrictions = restrictions;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param flavorId Specifies the CDN provider flavor ID to use. For a list of flavors, see the operation to list
+       *                 the available flavors. The minimum length for flavor_id is 3. The maximum length is 256.
+       * @return The CreateService builder.
+       */
+      public Builder flavorId(String flavorId) {
+         this.flavorId = flavorId;
+         return this;
+      }
+
+      public CreateService build() {
+         String missing = "";
+         if (name == null) {
+            missing += " name";
+         }
+         if (domains == null) {
+            missing += " domains";
+         }
+         if (origins == null) {
+            missing += " origins";
+         }
+         if (flavorId == null) {
+            missing += " flavorId";
+         }
+         if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+         }
+         CreateService result = new AutoValue_CreateService(
+               this.name,
+               this.domains,
+               this.origins,
+               ImmutableList.copyOf(this.caching),
+               ImmutableList.copyOf(this.restrictions),
+               this.flavorId);
+         return result;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Domain.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Domain.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Domain.java
new file mode 100644
index 0000000..e453ed6
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Domain.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.openstack.poppy.v1.domain;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * Representation of an OpenStack Poppy Domain.
+ */
+@AutoValue
+public abstract class Domain {
+   /**
+    * @see Builder#domain(String)
+    */
+   public abstract String getDomain();
+
+   /**
+    * @see Builder#protocol(Protocol)
+    */
+   @Nullable public abstract Protocol getProtocol();
+
+   @SerializedNames({ "domain", "protocol" })
+   private static Domain create(String domain, Protocol protocol) {
+      return builder().domain(domain).protocol(protocol).build();
+   }
+
+   public static Builder builder() {
+      return new AutoValue_Domain.Builder().protocol(null);
+   }
+   public Builder toBuilder() {
+      return builder()
+            .domain(getDomain())
+            .protocol(getProtocol());
+   }
+
+   public static final class Builder {
+      private String domain;
+      private Protocol protocol;
+      Builder() {
+      }
+      Builder(Domain source) {
+         domain(source.getDomain());
+         protocol(source.getProtocol());
+      }
+
+      /**
+       * Required.
+       * @param domain Specifies the domain used to access the assets on their website, for which a CNAME is given to
+       *             the CDN provider.
+       * @return The Domain builder.
+       */
+      public Domain.Builder domain(String domain) {
+         this.domain = domain;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param protocol Specifies the protocol used to access the assets on this domain. Only http or https are
+       *                 currently allowed. protocol defaults to http.
+       * @return The Domain builder.
+       */
+      public Domain.Builder protocol(Protocol protocol) {
+         this.protocol = protocol;
+         return this;
+      }
+
+      public Domain build() {
+         String missing = "";
+         if (domain == null) {
+            missing += " domain";
+         }
+         if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+         }
+         Domain result = new AutoValue_Domain(
+               this.domain,
+               this.protocol);
+         return result;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Error.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Error.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Error.java
new file mode 100644
index 0000000..5d54302
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Error.java
@@ -0,0 +1,39 @@
+/*
+ * 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.openstack.poppy.v1.domain;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * Representation of an OpenStack Poppy Error.
+ */
+@AutoValue
+abstract class Error {
+
+   /**
+    * @return Specifies an error message detailing why there is an error.
+    */
+   @Nullable abstract String getMessage();
+
+   @SerializedNames({ "message" })
+   static Error create(String message) {
+      return new AutoValue_Error(message);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Flavor.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Flavor.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Flavor.java
index e2a4e6a..a6cdbb8 100644
--- a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Flavor.java
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Flavor.java
@@ -23,22 +23,32 @@ import org.jclouds.json.SerializedNames;
 import org.jclouds.openstack.v2_0.domain.Link;
 
 import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 
 /**
  * Representation of an OpenStack Poppy CDN Flavor.
  */
 @AutoValue
 public abstract class Flavor {
-
+   /**
+    * @return Specifies the name of the flavor. The name must not exceed 64 bytes in length and is limited to Unicode,
+    * digits, underscores, and hyphens.
+    */
    public abstract String getId();
+
+   /**
+    * @return Specifies the list of providers mapped to this flavor.
+    */
    public abstract List<Provider> getProviders();
+
+   /**
+    * @return Specifies the self-navigating JSON document paths.
+    */
    public abstract Set<Link> getLinks();
 
    @SerializedNames({ "id", "providers", "links" })
-   public static Flavor create(String id, List<Provider> providers, Set<Link> links) {
-      return new AutoValue_Flavor(id, providers, links);
-   }
-
-   Flavor() {
+   private static Flavor create(String id, List<Provider> providers, Set<Link> links) {
+      return new AutoValue_Flavor(id, ImmutableList.copyOf(providers), ImmutableSet.copyOf(links));
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Origin.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Origin.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Origin.java
new file mode 100644
index 0000000..afc2505
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Origin.java
@@ -0,0 +1,143 @@
+/*
+ * 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.openstack.poppy.v1.domain;
+
+import java.util.List;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Representation of an OpenStack Poppy Origin.
+ */
+@AutoValue
+public abstract class Origin {
+   /**
+    * @see Builder#origin(String)
+    */
+   public abstract String getOrigin();
+
+   /**
+    * @see Builder#port(Integer)
+    */
+   @Nullable public abstract Integer getPort();
+
+   /**
+    * @see Builder#sslEnabled(Boolean)
+    */
+   @Nullable public abstract Boolean getSslEnabled();
+
+   /**
+    * @see Builder#rules(List)
+    */
+   @Nullable public abstract List<CachingRule> getRules();
+
+   @SerializedNames({ "origin", "port", "ssl", "rules" })
+   private static Origin create(String origin, int port, boolean sslEnabled, List<CachingRule> rules) {
+      return builder().origin(origin).port(port).sslEnabled(sslEnabled)
+            .rules(rules).build();
+   }
+
+   public static Builder builder() {
+      return new AutoValue_Origin.Builder();
+   }
+   public Builder toBuilder() {
+      return builder()
+            .origin(getOrigin())
+            .port(getPort())
+            .sslEnabled(getSslEnabled())
+            .rules(getRules());
+   }
+
+   public static final class Builder {
+      private String origin;
+      private Integer port;
+      private Boolean sslEnabled;
+      private List<CachingRule> rules;
+      Builder() {
+      }
+      Builder(Origin source) {
+         origin(source.getOrigin());
+         port(source.getPort());
+         sslEnabled(source.getSslEnabled());
+         rules(source.getRules());
+      }
+
+      /**
+       * Required.
+       * @param origin Specifies the URL or IP address from which to pull origin content. The minimum length for
+       *               origin is 3. The maximum length is 253.
+       * @return The Origin builder.
+       */
+      public Origin.Builder origin(String origin) {
+         this.origin = origin;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param port Specifies the port used to access the origin. The default is port 80. Note: Rackspace CDN cannot
+       *             be used with custom ports. Services are required to run on HTTP (80) and HTTPS (443) for the
+       *             origin servers.
+       * @return The Origin builder.
+       */
+      public Origin.Builder port(Integer port) {
+         this.port = port;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param sslEnabled Uses HTTPS to access the origin. The default is false.
+       * @return The Origin builder.
+       */
+      public Origin.Builder sslEnabled(Boolean sslEnabled) {
+         this.sslEnabled = sslEnabled;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param rules Specifies a collection of rules that define the conditions when this origin should be accessed.
+       *              If there is more than one origin, the rules parameter is required.
+       * @return The Origin builder.
+       */
+      public Origin.Builder rules(List<CachingRule> rules) {
+         this.rules = rules;
+         return this;
+      }
+
+      public Origin build() {
+         String missing = "";
+         if (origin == null) {
+            missing += " origin";
+         }
+         if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+         }
+         Origin result = new AutoValue_Origin(
+               this.origin,
+               this.port,
+               this.sslEnabled,
+               rules != null ? ImmutableList.copyOf(this.rules) : null);
+         return result;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Protocol.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Protocol.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Protocol.java
new file mode 100644
index 0000000..009bc56
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Protocol.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.poppy.v1.domain;
+
+/**
+ * Specifies the protocol used to access the assets on the domain. Only http or https are currently allowed.
+ * protocol defaults to http.
+ */
+public enum Protocol {
+   HTTP("http"),
+   HTTPS("https"),
+   /**
+    * An unexpected status jclouds could not recognize.
+    */
+   UNRECOGNIZED("unrecognized");
+
+   private String name;
+
+   private Protocol(String name) {
+      this.name = name;
+   }
+
+   @Override
+   public String toString() {
+      return name;
+   }
+
+   /*
+    * This provides GSON enum support in jclouds.
+    * @param name The string representation of this enum value.
+    * @return The corresponding enum value.
+    */
+   public static Protocol fromValue(String name) {
+      if (name != null) {
+         for (Protocol value : Protocol.values()) {
+            if (name.equalsIgnoreCase(value.name)) {
+               return value;
+            }
+         }
+         return UNRECOGNIZED;
+      }
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Provider.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Provider.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Provider.java
index 06be476..8b68435 100644
--- a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Provider.java
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Provider.java
@@ -28,15 +28,19 @@ import com.google.auto.value.AutoValue;
  */
 @AutoValue
 public abstract class Provider {
+   /**
+    * @return The name of the provider. The name must not exceed 64 bytes in length and is limited to
+    * Unicode, digits, underscores, and hyphens.
+    */
+   public abstract String getProvider();
 
-   public abstract String getId();
+   /**
+    * @return Specifies a list with an href where rel is provider_url.
+    */
    public abstract Set<Link> getLinks();
 
    @SerializedNames({ "provider", "links" })
-   public static Provider create(String id, Set<Link> links) {
-      return new AutoValue_Provider(id, links);
-   }
-
-   Provider() {
+   private static Provider create(String provider, Set<Link> links) {
+      return new AutoValue_Provider(provider, links);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Restriction.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Restriction.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Restriction.java
new file mode 100644
index 0000000..9bab8de
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Restriction.java
@@ -0,0 +1,101 @@
+/*
+ * 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.openstack.poppy.v1.domain;
+
+import java.util.List;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Representation of an OpenStack Poppy Access Restriction.
+ */
+@AutoValue
+public abstract class Restriction {
+   /**
+    * @see Builder#name(String)
+    */
+   public abstract String getName();
+
+   /**
+    * @see Builder#rules(List)
+    */
+   @Nullable public abstract List<RestrictionRule> getRules();
+
+   @SerializedNames({ "name", "rules" })
+   private static Restriction create(String name, List<RestrictionRule> rules) {
+      return builder().name(name).rules(rules).build();
+   }
+
+   public static Builder builder() {
+      return new AutoValue_Restriction.Builder();
+   }
+   public Builder toBuilder(){
+      return builder()
+            .name(getName())
+            .rules(getRules());
+   }
+
+   public static final class Builder {
+      private String name;
+      private List<RestrictionRule> rules;
+      Builder() {
+      }
+      Builder(Restriction source) {
+         name(source.getName());
+         rules(source.getRules());
+      }
+
+      /**
+       * Required.
+       * @param name Specifies the name of this restriction. The minimum length for name is 1.
+       *             The maximum length is 256.
+       * @return The Restriction builder.
+       */
+      public Restriction.Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param rules Specifies a collection of rules that determine if this restriction should be applied to an asset.
+       * @return The Restriction builder.
+       */
+      public Restriction.Builder rules(List<RestrictionRule> rules) {
+         this.rules = rules;
+         return this;
+      }
+
+      public Restriction build() {
+         String missing = "";
+         if (name == null) {
+            missing += " name";
+         }
+         if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+         }
+         Restriction result = new AutoValue_Restriction(
+               this.name,
+               rules != null ? ImmutableList.copyOf(this.rules) : null);
+         return result;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/RestrictionRule.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/RestrictionRule.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/RestrictionRule.java
new file mode 100644
index 0000000..50ff8d5
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/RestrictionRule.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.openstack.poppy.v1.domain;
+
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+
+@AutoValue
+public abstract class RestrictionRule {
+   /**
+    * @see Builder#name(String)
+    */
+   public abstract String getName();
+
+   /**
+    * @see Builder#httpHost(String)
+    */
+   public abstract String getHttpHost();
+
+   @SerializedNames({ "name", "referrer" })
+   private static RestrictionRule create(String name, String httpHost) {
+      return builder().name(name).httpHost(httpHost).build();
+   }
+
+   public static Builder builder() {
+      return new AutoValue_RestrictionRule.Builder();
+   }
+
+   public Builder toBuilder(){
+      return builder()
+            .name(getName())
+            .httpHost(getHttpHost());
+   }
+
+   public static final class Builder {
+      private String name;
+      private String httpHost;
+      Builder() {
+      }
+      Builder(RestrictionRule source) {
+         name(source.getName());
+         httpHost(source.getHttpHost());
+      }
+
+      /**
+       * Required.
+       * @param name Specifies the name of this rule. The minimum length for name is 1. The maximum length is 256.
+       * @return The RestrictionRule builder.
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param httpHost Specifies the http host that requests must come from. The minimum length for referrer is 3.
+       *                   The maximum length is 1024.
+       * @return The RestrictionRule builder.
+       */
+      public Builder httpHost(String httpHost) {
+         this.httpHost = httpHost;
+         return this;
+      }
+
+      public RestrictionRule build() {
+         String missing = "";
+         if (name == null) {
+            missing += " name";
+         }
+         if (httpHost == null) {
+            missing += " httpHost";
+         }
+         if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+         }
+         RestrictionRule result = new AutoValue_RestrictionRule(
+               this.name,
+               this.httpHost);
+         return result;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Service.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Service.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Service.java
new file mode 100644
index 0000000..0176979
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Service.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.openstack.poppy.v1.domain;
+
+import java.util.List;
+import java.util.Set;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+import org.jclouds.openstack.v2_0.domain.Link;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Representation of an OpenStack Poppy Service.
+ */
+@AutoValue
+public abstract class Service {
+
+   /**
+    * @return Specifies the service ID that represents distributed content. The value is a UUID, such as
+    * 96737ae3-cfc1-4c72-be88-5d0e7cc9a3f0, that is generated by the server.
+    */
+   public abstract String getId();
+
+   /**
+    * @return Specifies the name of the service.
+    */
+   public abstract String getName();
+
+   /**
+    * @return Specifies a list of domains used by users to access their website.
+    */
+   public abstract List<Domain> getDomains();
+
+   /**
+    * @return Specifies a list of origin domains or IP addresses where the original assets are stored.
+    */
+   public abstract List<Origin> getOrigins();
+
+   /**
+    * @return Specifies the TTL rules for the assets under this service. Supports wildcards for fine-grained control.
+    */
+   @Nullable public abstract List<Caching> getCaching();
+
+   /**
+    * @return Specifies the restrictions that define who can access assets (content from the CDN cache).
+    */
+   @Nullable public abstract List<Restriction> getRestrictions();
+
+   /**
+    * @return Specifies the CDN provider flavor ID to use. For a list of flavors, see the operation to list the
+    * available flavors.
+    */
+   public abstract String getFlavorId();
+
+   /**
+    * @return Specifies the current status of the service.
+    */
+   public abstract ServiceStatus getStatus();
+
+   /**
+    * @return Specifies the list of errors that occurred during the previous service action.
+    */
+   @Nullable public abstract List<Error> getErrors();
+
+   /**
+    * @return Specifies the self-navigating JSON document paths.
+    */
+   public abstract Set<Link> getLinks();
+
+   @SerializedNames({ "id", "name", "domains", "origins", "caching", "restrictions", "flavor_id",
+      "status", "errors", "links" })
+   private static Service create(String id, String name, List<Domain> domains,
+         List<Origin> origins, List<Caching> caching, List<Restriction> restrictions,
+         String flavorId, ServiceStatus status, List<Error> errors, Set<Link> links) {
+      return new AutoValue_Service(
+            id,
+            name,
+            ImmutableList.copyOf(domains),
+            ImmutableList.copyOf(origins),
+            caching != null ? ImmutableList.copyOf(caching) : null,
+            restrictions != null ? ImmutableList.copyOf(restrictions) : null,
+            flavorId,
+            status,
+            errors != null ? ImmutableList.copyOf(errors) : null,
+            ImmutableSet.copyOf(links));
+   }
+
+   public UpdateService.Builder toUpdatableService() {
+      return UpdateService.builder()
+            .name(getName())
+            .domains(getDomains())
+            .origins(getOrigins())
+            .caching(getCaching())
+            .restrictions(getRestrictions())
+            .flavorId(getFlavorId());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/ServiceStatus.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/ServiceStatus.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/ServiceStatus.java
new file mode 100644
index 0000000..9d14e72
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/ServiceStatus.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jclouds.openstack.poppy.v1.domain;
+
+public enum ServiceStatus {
+   /**
+    * Specifies that the service is currently being created and deployed.
+    */
+   CREATE_IN_PROGRESS("create_in_progress "),
+   /**
+    * Specifies that the service has been deployed and is ready to use.
+    */
+   DEPLOYED("deployed "),
+   /**
+    * Specifies that the service is currently being updated.
+    */
+   UPDATE_IN_PROGRESS("update_in_progress "),
+   /**
+    * Specifies that the service is currently being deleted.
+    */
+   DELETE_IN_PROGRESS("delete_in_progress "),
+   /**
+    * Specifies that the previous operation on the service failed to create, deploy, update, or delete.
+    * Looks for the errors for details.
+    * @see Service#getErrors()
+    */
+   FAILED("failed "),
+   /**
+    * An unexpected status jclouds could not recognize.
+    */
+   UNRECOGNIZED("unrecognized");
+
+   private String name;
+
+   private ServiceStatus(String name) {
+      this.name = name;
+   }
+
+   @Override
+   public String toString() {
+      return name;
+   }
+
+   /*
+    * This provides GSON enum support in jclouds.
+    * @param name The string representation of this enum value.
+    * @return The corresponding enum value.
+    */
+   public static ServiceStatus fromValue(String name) {
+      if (name != null) {
+         for (ServiceStatus value : ServiceStatus.values()) {
+            if (name.equalsIgnoreCase(value.name)) {
+               return value;
+            }
+         }
+         return UNRECOGNIZED;
+      }
+      return null;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Services.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Services.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Services.java
new file mode 100644
index 0000000..34c459c
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/Services.java
@@ -0,0 +1,36 @@
+/*
+ * 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.openstack.poppy.v1.domain;
+
+import java.beans.ConstructorProperties;
+
+import org.jclouds.openstack.v2_0.domain.Link;
+import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * A collection of Networks
+ */
+public class Services extends PaginatedCollection<Service> {
+   public static final Services EMPTY = new Services(ImmutableSet.<Service> of(), ImmutableSet.<Link> of());
+
+   @ConstructorProperties({"services", "links"})
+   protected Services(Iterable<Service> services, Iterable<Link> servicesLinks) {
+      super(services, servicesLinks);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/UpdateService.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/UpdateService.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/UpdateService.java
new file mode 100644
index 0000000..dc4b070
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/domain/UpdateService.java
@@ -0,0 +1,193 @@
+/*
+ * 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.openstack.poppy.v1.domain;
+
+import java.util.List;
+
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.json.SerializedNames;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Representation of updatable options for an OpenStack Poppy Service.
+ */
+@AutoValue
+public abstract class UpdateService {
+   /**
+    * @see Builder#name(String)
+    */
+   public abstract String getName();
+
+   /**
+    * @see Builder#domains(List)
+    */
+   public abstract List<Domain> getDomains();
+
+   /**
+    * @see Builder#origins(List)
+    */
+   public abstract List<Origin> getOrigins();
+
+   /**
+    * @see Builder#caching(List)
+    */
+   @Nullable public abstract List<Caching> getCaching();
+
+   /**
+    * @see Builder#restrictions(List)
+    */
+   @Nullable public abstract List<Restriction> getRestrictions();
+
+   /**
+    * @see Builder#flavorId(String)
+    */
+   public abstract String getFlavorId();
+
+   public static Builder builder() {
+      return new AutoValue_UpdateService.Builder().caching(null).restrictions(null);
+   }
+   public Builder toBuilder() {
+      return builder()
+            .name(getName())
+            .domains(getDomains())
+            .origins(getOrigins())
+            .caching(getCaching())
+            .restrictions(getRestrictions())
+            .flavorId(getFlavorId());
+   }
+
+   @SerializedNames({ "name", "domains", "origins", "caching", "restrictions", "flavor_id" })
+   private static UpdateService create(String name, List<Domain> domains, List<Origin> origins, List<Caching> caching,
+         List<Restriction> restrictions, String flavorId) {
+      return builder()
+            .name(name)
+            .domains(domains)
+            .origins(origins)
+            .caching(caching)
+            .restrictions(restrictions)
+            .flavorId(flavorId).build();
+   }
+
+   public static final class Builder {
+      private String name;
+      private List<Domain> domains;
+      private List<Origin> origins;
+      private List<Caching> caching;
+      private List<Restriction> restrictions;
+      private String flavorId;
+      Builder() {
+      }
+      Builder(UpdateService source) {
+         name(source.getName());
+         domains(source.getDomains());
+         origins(source.getOrigins());
+         caching(source.getCaching());
+         restrictions(source.getRestrictions());
+         flavorId(source.getFlavorId());
+      }
+
+      /**
+       * Required.
+       * @param name Specifies the name of the service. The minimum length for name is 3. The maximum length is 256.
+       * @return The UpdateService builder.
+       */
+      public Builder name(String name) {
+         this.name = name;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param domains Specifies a list of domains used by users to access their website.
+       * @return The UpdateService builder.
+       */
+      public Builder domains(List<Domain> domains) {
+         this.domains = domains;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param origins Specifies a list of origin domains or IP addresses where the original assets are stored.
+       * @return The UpdateService builder.
+       */
+      public Builder origins(List<Origin> origins) {
+         this.origins = origins;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param caching Specifies the TTL rules for the assets under this service. Supports wildcards for fine-grained control.
+       * @return The UpdateService builder.
+       */
+      public Builder caching(List<Caching> caching) {
+         this.caching = caching;
+         return this;
+      }
+
+      /**
+       * Optional.
+       * @param restrictions Specifies the restrictions that define who can access assets (content from the CDN cache).
+       * @return The UpdateService builder.
+       */
+      public Builder restrictions(List<Restriction> restrictions) {
+         this.restrictions = restrictions;
+         return this;
+      }
+
+      /**
+       * Required.
+       * @param flavorId Specifies the CDN provider flavor ID to use. For a list of flavors, see the operation to list
+       *                 the available flavors. The minimum length for flavor_id is 3. The maximum length is 256.
+       * @return The UpdateService builder.
+       */
+      public Builder flavorId(String flavorId) {
+         this.flavorId = flavorId;
+         return this;
+      }
+
+      public UpdateService build() {
+         String missing = "";
+         if (name == null) {
+            missing += " name";
+         }
+         if (domains == null) {
+            missing += " domains";
+         }
+         if (origins == null) {
+            missing += " origins";
+         }
+         if (flavorId == null) {
+            missing += " flavorId";
+         }
+         if (!missing.isEmpty()) {
+            throw new IllegalStateException("Missing required properties:" + missing);
+         }
+         UpdateService result = new AutoValue_UpdateService(
+               this.name,
+               this.domains,
+               this.origins,
+               caching != null ? ImmutableList.copyOf(this.caching) : null,
+               restrictions != null ? ImmutableList.copyOf(this.restrictions) : null,
+               this.flavorId);
+         return result;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/fallbacks/PoppyFallbacks.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/fallbacks/PoppyFallbacks.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/fallbacks/PoppyFallbacks.java
new file mode 100644
index 0000000..10b0f46
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/fallbacks/PoppyFallbacks.java
@@ -0,0 +1,36 @@
+/*
+ * 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.openstack.poppy.v1.fallbacks;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.in;
+import static com.google.common.primitives.Ints.asList;
+import static org.jclouds.http.HttpUtils.returnValueOnCodeOrNull;
+
+import org.jclouds.Fallback;
+
+public final class PoppyFallbacks {
+   private PoppyFallbacks() {
+   }
+
+   public static class FalseOn500or503 implements Fallback<Boolean> {
+      @Override
+      public Boolean createOrPropagate(Throwable t) throws Exception {
+         return returnValueOnCodeOrNull(checkNotNull(t, "throwable"), false, in(asList(500, 503)));
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/FlavorApi.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/FlavorApi.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/FlavorApi.java
index ee214ad..5e498ba 100644
--- a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/FlavorApi.java
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/FlavorApi.java
@@ -38,7 +38,7 @@ import com.google.common.annotations.Beta;
 import com.google.common.collect.FluentIterable;
 
 /**
- * Provides access to Flavor features.
+ * Provides access to OpenStack Poppy Flavor features.
  */
 @Beta
 @RequestFilters(AuthenticateRequest.class)
@@ -46,13 +46,25 @@ import com.google.common.collect.FluentIterable;
 @Endpoint(CDN.class)
 @Path("/flavors")
 public interface FlavorApi {
-
+   /**
+    * Gets a list of Flavors.
+    * <p/>
+    * If there are no Flavors, this method will fallback to an empty collection.
+    *
+    * @return an {@code Iterable} collection.
+    */
    @Named("flavor:list")
    @GET
    @SelectJson("flavors")
    @Fallback(EmptyFluentIterableOnNotFoundOr404.class)
    FluentIterable<Flavor> list();
 
+   /**
+    * Gets a Flavor.
+    *
+    * @param id  the id of the {@code Flavor}
+    * @return the {@code Flavor} for the specified id, otherwise {@code null}
+    */
    @Named("flavor:get")
    @GET
    @Path("/{id}")

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/ServiceApi.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/ServiceApi.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/ServiceApi.java
new file mode 100644
index 0000000..d1b7575
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/features/ServiceApi.java
@@ -0,0 +1,147 @@
+/*
+ * 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.openstack.poppy.v1.features;
+
+import java.net.URI;
+
+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.Fallbacks;
+import org.jclouds.Fallbacks.EmptyPagedIterableOnNotFoundOr404;
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.collect.PagedIterable;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.openstack.keystone.v2_0.KeystoneFallbacks.EmptyPaginatedCollectionOnNotFoundOr404;
+import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
+import org.jclouds.openstack.poppy.v1.config.CDN;
+import org.jclouds.openstack.poppy.v1.domain.CreateService;
+import org.jclouds.openstack.poppy.v1.domain.Service;
+import org.jclouds.openstack.poppy.v1.domain.UpdateService;
+import org.jclouds.openstack.poppy.v1.functions.ParseServiceURIFromHeaders;
+import org.jclouds.openstack.poppy.v1.functions.ParseServices;
+import org.jclouds.openstack.poppy.v1.functions.ServicesToPagedIterable;
+import org.jclouds.openstack.poppy.v1.mapbinders.JSONPatchUpdate;
+import org.jclouds.openstack.v2_0.domain.PaginatedCollection;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+import org.jclouds.rest.annotations.BinderParam;
+import org.jclouds.rest.annotations.Endpoint;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.MapBinder;
+import org.jclouds.rest.annotations.PATCH;
+import org.jclouds.rest.annotations.PayloadParam;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.Transform;
+import org.jclouds.rest.binders.BindToJsonPayload;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Provides access to OpenStack Poppy Service features.
+ */
+@Beta
+@RequestFilters(AuthenticateRequest.class)
+@Consumes(MediaType.APPLICATION_JSON)
+@Endpoint(CDN.class)
+@Path("/services")
+public interface ServiceApi {
+   /**
+    * Returns all Services currently defined in Poppy for the tenant.
+    *
+    * @return the list of all networks configured for the tenant in a a paged collection.
+    */
+   @Named("service:list")
+   @GET
+   @ResponseParser(ParseServices.class)
+   @Transform(ServicesToPagedIterable.class)
+   @Fallback(EmptyPagedIterableOnNotFoundOr404.class)
+   PagedIterable<Service> list();
+
+   /**
+    * Lists Services by providing a specific set of listing options.
+    * @param options Describes how services should be listed.
+    */
+   @Named("service:list")
+   @GET
+   @ResponseParser(ParseServices.class)
+   @Fallback(EmptyPaginatedCollectionOnNotFoundOr404.class)
+   PaginatedCollection<Service> list(PaginationOptions options);
+
+   /**
+    * Gets a specific Service by id (UUID).
+    *
+    * @param id  the id of the {@code Service}
+    * @return the {@code Service} for the specified id, otherwise {@code null}
+    */
+   @Named("service:get")
+   @GET
+   @Path("/{id}")
+   @Fallback(NullOnNotFoundOr404.class)
+   @Nullable
+   Service get(@PathParam("id") String id);
+
+   /**
+    * Creates a Service.
+    *
+    * @param createService  Describes the new {@code Service} to be created.
+    * @return a URI to the created {@code Service}.
+    */
+   @Named("service:create")
+   @POST
+   @ResponseParser(ParseServiceURIFromHeaders.class)
+   @Produces(MediaType.APPLICATION_JSON)
+   @Nullable
+   URI create(@BinderParam(BindToJsonPayload.class) CreateService createService);
+
+   /**
+    * Deletes the specified {@code Service}
+    *
+    * @param id the id of the {@code Service} to delete.
+    * @return true if delete was successful, false if not.
+    */
+   @Named("network:delete")
+   @DELETE
+   @Path("/{id}")
+   @Fallback(Fallbacks.FalseOnNotFoundOr404.class)
+   boolean delete(@PathParam("id") String id);
+
+   /**
+    * Updates a service by applying JSONPatch internally.
+    * This requires providing your updatable {@code Service} and the target {@code UpdateService}.
+    * They will be converted to JSON, diffed, and a JSON patch will be generated by jclouds automatically.
+    *
+    * @param service Source JSON
+    * @param updateService Target JSON
+    * @return a URI to the created service
+    * @see <a href="https://tools.ietf.org/html/rfc6902">JSONPatch RFC</a>
+    */
+   @Named("service:update")
+   @PATCH
+   @Path("/{id}")
+   @ResponseParser(ParseServiceURIFromHeaders.class)
+   @MapBinder(JSONPatchUpdate.class)
+   @Nullable
+   URI update(@PathParam("id") String id, @PayloadParam("service") Service service, @PayloadParam("updateService") UpdateService updateService);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ParseServiceURIFromHeaders.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ParseServiceURIFromHeaders.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ParseServiceURIFromHeaders.java
new file mode 100644
index 0000000..5f2861a
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ParseServiceURIFromHeaders.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.openstack.poppy.v1.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpResponse;
+import org.jclouds.openstack.poppy.v1.domain.Service;
+
+import com.google.common.base.Function;
+import com.google.common.net.HttpHeaders;
+
+/**
+ * Parses the {@link Service} URI from the Location header of the HTTP Response.
+ */
+@Singleton
+public class ParseServiceURIFromHeaders implements Function<HttpResponse, URI> {
+
+	@Override
+   public URI apply(HttpResponse response) {
+     String locationUri =  checkNotNull(response.getFirstHeaderOrNull(HttpHeaders.LOCATION),
+           HttpHeaders.LOCATION);
+     return URI.create(locationUri);
+    }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ParseServices.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ParseServices.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ParseServices.java
new file mode 100644
index 0000000..7c787ea
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ParseServices.java
@@ -0,0 +1,38 @@
+/*
+ * 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.openstack.poppy.v1.functions;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.functions.ParseJson;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.poppy.v1.domain.Services;
+
+import com.google.inject.TypeLiteral;
+
+/**
+ * Used by jclouds to provide more specific collections and fallbacks.
+ */
+@Singleton
+public class ParseServices extends ParseJson<Services> {
+
+   @Inject
+   ParseServices(Json json) {
+      super(json, TypeLiteral.get(Services.class));
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ServicesToPagedIterable.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ServicesToPagedIterable.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ServicesToPagedIterable.java
new file mode 100644
index 0000000..a8b841a
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/functions/ServicesToPagedIterable.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.openstack.poppy.v1.functions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.inject.Inject;
+
+import org.jclouds.collect.IterableWithMarker;
+import org.jclouds.collect.internal.Arg0ToPagedIterable;
+import org.jclouds.openstack.poppy.v1.PoppyApi;
+import org.jclouds.openstack.poppy.v1.domain.Service;
+import org.jclouds.openstack.poppy.v1.features.ServiceApi;
+import org.jclouds.openstack.v2_0.options.PaginationOptions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+
+/**
+ * Makes Services work as a PagedIterable.
+ */
+public class ServicesToPagedIterable extends Arg0ToPagedIterable.FromCaller<Service, ServicesToPagedIterable> {
+
+   private final PoppyApi api;
+
+   @Inject
+   protected ServicesToPagedIterable(PoppyApi api) {
+      this.api = checkNotNull(api, "api");
+   }
+
+   @Override
+   protected Function<Object, IterableWithMarker<Service>> markerToNextForArg0(Optional<Object> arg0) {
+      final ServiceApi serviceApi = api.getServiceApi();
+      return new Function<Object, IterableWithMarker<Service>>() {
+
+         @SuppressWarnings("unchecked")
+         @Override
+         public IterableWithMarker<Service> apply(Object input) {
+            PaginationOptions paginationOptions = PaginationOptions.class.cast(input);
+            return IterableWithMarker.class.cast(serviceApi.list(paginationOptions));
+         }
+
+         @Override
+         public String toString() {
+            return "listServices()";
+         }
+      };
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/mapbinders/JSONPatchUpdate.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/mapbinders/JSONPatchUpdate.java b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/mapbinders/JSONPatchUpdate.java
new file mode 100644
index 0000000..77983b4
--- /dev/null
+++ b/openstack-poppy/src/main/java/org/jclouds/openstack/poppy/v1/mapbinders/JSONPatchUpdate.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.openstack.poppy.v1.mapbinders;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.jclouds.http.HttpRequest;
+import org.jclouds.json.Json;
+import org.jclouds.openstack.poppy.v1.domain.Service;
+import org.jclouds.rest.MapBinder;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.fge.jsonpatch.diff.JsonDiff;
+import com.google.inject.Inject;
+
+/**
+ * This will create a JSONPatch out of a Service and an UpdateService.
+ *
+ * User side:
+ * Get a Service with api.get(service_id)
+ * Get a UpdateService builder by using Service.toUpdatableService()
+ *    This step will provide an interface that exposes the updatable JSON values to the user.
+ * Use the UpdateService.Builder instance to modify and build() a new UpdateService.
+ * Send the original Service and the new UpdateService to the api.update method.
+ *
+ * jclouds side:
+ * Convert the Service to UpdateService, but don't change it (this is the source).
+ * Serialize both source and target to String
+ * Diff to create JSONPatch using dependency.
+ * Send the JSONPatch in the request.
+ *
+ * JSONPatch RFC:
+ * https://tools.ietf.org/html/rfc6902
+ */
+public class JSONPatchUpdate implements MapBinder {
+   @Inject
+   Json json;
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
+      String jsonPatch = null;
+      Service service = (Service) postParams.get("service");
+
+      //Json json = Guice.createInjector(new GsonModule()).getInstance(Json.class);
+
+      String targetService = json.toJson(postParams.get("updateService"));
+      String sourceService = json.toJson(service.toUpdatableService().build());
+
+      ObjectMapper mapper = new ObjectMapper();
+      try {
+         jsonPatch = JsonDiff.asJson(mapper.readTree(sourceService), mapper.readTree(targetService)).toString();
+      } catch (IOException e) {
+         throw new RuntimeException("Could not create a JSONPatch", e);
+      }
+
+      return bindToRequest(request, (Object) jsonPatch);
+   }
+
+   @Override
+   public <R extends HttpRequest> R bindToRequest(R request, Object input) {
+      request.setPayload((String) input);
+      request.getPayload().getContentMetadata().setContentType("application/json");
+      return request;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-openstack/blob/3b609456/openstack-poppy/src/test/java/org/jclouds/openstack/poppy/v1/features/FlavorApiLiveTest.java
----------------------------------------------------------------------
diff --git a/openstack-poppy/src/test/java/org/jclouds/openstack/poppy/v1/features/FlavorApiLiveTest.java b/openstack-poppy/src/test/java/org/jclouds/openstack/poppy/v1/features/FlavorApiLiveTest.java
index 508e3fd..6ca5691 100644
--- a/openstack-poppy/src/test/java/org/jclouds/openstack/poppy/v1/features/FlavorApiLiveTest.java
+++ b/openstack-poppy/src/test/java/org/jclouds/openstack/poppy/v1/features/FlavorApiLiveTest.java
@@ -66,6 +66,5 @@ public class FlavorApiLiveTest extends BasePoppyApiLiveTest {
          assertEquals(oneFlavor.getProviders(), flavor.getProviders());
          assertEquals(oneFlavor.getLinks(), flavor.getLinks());
       }
-
    }
 }