You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ha...@apache.org on 2015/08/09 04:55:28 UTC

[21/28] incubator-brooklyn git commit: brooklyn-rest-api: add org.apache package prefix

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AccessSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AccessSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AccessSummary.java
new file mode 100644
index 0000000..8d5aefa
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/AccessSummary.java
@@ -0,0 +1,74 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Map;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+@Beta
+public class AccessSummary implements Serializable {
+
+    private static final long serialVersionUID = 5097292906225042890L;
+    
+    private final boolean locationProvisioningAllowed;
+    private final Map<String, URI> links;
+
+    public AccessSummary(
+            @JsonProperty("locationProvisioningAllowed") boolean locationProvisioningAllowed,
+            @JsonProperty("links") Map<String, URI> links
+    ) {
+        this.locationProvisioningAllowed = locationProvisioningAllowed;
+        this.links = (links == null) ? ImmutableMap.<String, URI>of() : ImmutableMap.copyOf(links);
+      }
+
+    public boolean isLocationProvisioningAllowed() {
+        return locationProvisioningAllowed;
+    }
+
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+    
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof AccessSummary)) return false;
+        AccessSummary other = (AccessSummary) o;
+        return locationProvisioningAllowed == other.isLocationProvisioningAllowed();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(locationProvisioningAllowed);
+    }
+
+    @Override
+    public String toString() {
+        return "AccessSummary{" +
+                "locationProvisioningAllowed='" + locationProvisioningAllowed + '\'' +
+                ", links=" + links +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApiError.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApiError.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApiError.java
new file mode 100644
index 0000000..5695ad5
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApiError.java
@@ -0,0 +1,208 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.Serializable;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
+
+public class ApiError implements Serializable {
+
+    private static final long serialVersionUID = -8244515572813244686L;
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static ApiError of(Throwable t) {
+        return builderFromThrowable(t).build();
+    }
+    
+    public static ApiError of(String message) {
+        return builder().message(message).build();
+    }
+    
+    /** @deprecated since 0.7.0; use {@link #builderFromThrowable(Throwable)} */
+    @Deprecated
+    public static Builder fromThrowable(Throwable t) {
+        return builderFromThrowable(t);
+    }
+    
+    /**
+     * @return An {@link ApiError.Builder} whose message is initialised to either the throwable's
+     *         message or the throwable's class name if the message is null and whose details are
+     *         initialised to the throwable's stack trace.
+     */
+    public static Builder builderFromThrowable(Throwable t) {
+        checkNotNull(t, "throwable");
+        String message = Optional.fromNullable(t.getMessage())
+                .or(t.getClass().getName());
+        return builder()
+                .message(message)
+                .details(Throwables.getStackTraceAsString(t));
+    }
+
+    public static class Builder {
+        private String message;
+        private String details;
+        private Integer errorCode;
+
+        public Builder message(String message) {
+            this.message = checkNotNull(message, "message");
+            return this;
+        }
+
+        public Builder details(String details) {
+            this.details = checkNotNull(details, "details");
+            return this;
+        }
+
+        public Builder errorCode(Status errorCode) {
+            return errorCode(errorCode.getStatusCode());
+        }
+        
+        public Builder errorCode(Integer errorCode) {
+            this.errorCode = errorCode;
+            return this;
+        }
+        
+        /** as {@link #prefixMessage(String, String)} with default separator of `: ` */
+        public Builder prefixMessage(String prefix) {
+            return prefixMessage(prefix, ": ");
+        }
+        
+        /** puts a prefix in front of the message, with the given separator if there is already a message;
+         * if there is no message, it simply sets the prefix as the message
+         */
+        public Builder prefixMessage(String prefix, String separatorIfMessageNotBlank) {
+            if (Strings.isBlank(message)) message(prefix);
+            else message(prefix+separatorIfMessageNotBlank+message);
+            return this;
+        }
+        
+        public ApiError build() {
+            return new ApiError(message, details, errorCode);
+        }
+
+        /** @deprecated since 0.7.0; use {@link #copy(ApiError)} */
+        @Deprecated
+        public Builder fromApiError(ApiError error) {
+            return copy(error);
+        }
+        
+        public Builder copy(ApiError error) {
+            return this
+                    .message(error.message)
+                    .details(error.details)
+                    .errorCode(error.error);
+        }
+        
+        public String getMessage() {
+            return message;
+        }
+    }
+
+    private final String message;
+    
+    @JsonSerialize(include=Inclusion.NON_EMPTY)
+    private final String details;
+
+    @JsonSerialize(include=Inclusion.NON_NULL)
+    private final Integer error;
+
+    public ApiError(String message) { this(message, null); }
+    public ApiError(String message, String details) { this(message, details, null); }
+    public ApiError(
+            @JsonProperty("message") String message,
+            @JsonProperty("details") String details,
+            @JsonProperty("error") Integer error) {
+        this.message = checkNotNull(message, "message");
+        this.details = details != null ? details : "";
+        this.error = error;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public String getDetails() {
+        return details;
+    }
+
+    public Integer getError() {
+        return error;
+    }
+    
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if (other == null || getClass() != other.getClass()) return false;
+        ApiError that = ApiError.class.cast(other);
+        return Objects.equal(this.message, that.message) &&
+                Objects.equal(this.details, that.details) &&
+                Objects.equal(this.error, that.error);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(message, details, error);
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(this)
+                .add("message", message)
+                .add("details", details)
+                .add("error", error)
+                .toString();
+    }
+
+    public Response asBadRequestResponseJson() {
+        return asResponse(Status.BAD_REQUEST, MediaType.APPLICATION_JSON_TYPE);
+    }
+
+    public Response asResponse(Status defaultStatus, MediaType type) {
+        return Response.status(error!=null ? error : defaultStatus!=null ? defaultStatus.getStatusCode() : Status.INTERNAL_SERVER_ERROR.getStatusCode())
+            .type(type)
+            .entity(this)
+            .build();
+    }
+    
+    public Response asResponse(MediaType type) {
+        return asResponse(null, type);
+    }
+    
+    public Response asJsonResponse() {
+        return asResponse(MediaType.APPLICATION_JSON_TYPE);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java
new file mode 100644
index 0000000..8e82c8e
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSpec.java
@@ -0,0 +1,181 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+public class ApplicationSpec implements HasName, Serializable {
+
+    private static final long serialVersionUID = -7090404504233835343L;
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private String name;
+        private String type;
+        private Set<EntitySpec> entities;
+        private Set<String> locations;
+        private Map<String, String> config;
+
+        public Builder from(ApplicationSpec spec) {
+            this.name = spec.name;
+            this.entities = spec.entities;
+            this.locations = spec.locations;
+            return this;
+        }
+
+        public Builder name(String name) {
+            this.name = name;
+            return this;
+        }
+
+        public Builder type(String type) {
+            this.type = type;
+            return this;
+        }
+
+        public Builder entities(Set<EntitySpec> entities) {
+            this.entities = entities;
+            return this;
+        }
+
+        public Builder locations(Set<String> locations) {
+            this.locations = locations;
+            return this;
+        }
+
+        public Builder config(Map<String, String> config) {
+            this.config = config;
+            return this;
+        }
+
+        public ApplicationSpec build() {
+            return new ApplicationSpec(name, type, entities, locations, config);
+        }
+    }
+
+    private final String name;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final String type;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final Set<EntitySpec> entities;
+    private final Set<String> locations;
+    @JsonSerialize(include = Inclusion.NON_EMPTY)
+    private final Map<String, String> config;
+
+  public ApplicationSpec(
+          @JsonProperty("name") String name,
+          @JsonProperty("type") String type,
+          @JsonProperty("entities") Set<EntitySpec> entities,
+          @JsonProperty("locations") Collection<String> locations,
+          @JsonProperty("config") Map<String, String> config) {
+      this.name = name;
+      this.type = type;
+      if (entities==null) {
+          this.entities = null;
+      } else {
+          this.entities = (entities.isEmpty() && type!=null) ? null : ImmutableSet.copyOf(entities);
+      }
+      this.locations = ImmutableSet.copyOf(checkNotNull(locations, "locations must be provided for an application spec"));
+      this.config = config == null ? Collections.<String, String>emptyMap() : ImmutableMap.<String, String>copyOf(config);
+      if (this.entities!=null && this.type!=null) throw new IllegalStateException("cannot supply both type and entities for an application spec");
+      // valid for both to be null, e.g. for an anonymous type 
+//      if (this.entities==null && this.type==null) throw new IllegalStateException("must supply either type or entities for an application spec");
+  }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public Set<EntitySpec> getEntities() {
+        return entities;
+    }
+
+    public Set<String> getLocations() {
+        return locations;
+    }
+
+    public Map<String, String> getConfig() {
+        return config;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        ApplicationSpec that = (ApplicationSpec) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+        if (type != null ? !type.equals(that.type) : that.type != null)
+            return false;
+        if (entities != null ? !entities.equals(that.entities) : that.entities != null)
+            return false;
+        if (locations != null ? !locations.equals(that.locations) : that.locations != null)
+            return false;
+        if (config != null ? !config.equals(that.config) : that.config != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (type != null ? type.hashCode() : 0);
+        result = 31 * result + (entities != null ? entities.hashCode() : 0);
+        result = 31 * result + (locations != null ? locations.hashCode() : 0);
+        result = 31 * result + (config != null ? config.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "ApplicationSpec{"
+                + "name='" + name + '\''
+                + ", type=" + type
+                + ", entitySpecs=" + entities
+                + ", locations=" + locations
+                + ", config=" + config
+                + '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSummary.java
new file mode 100644
index 0000000..3d8ead9
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ApplicationSummary.java
@@ -0,0 +1,117 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Map;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import com.google.common.collect.ImmutableMap;
+
+public class ApplicationSummary implements HasId, Serializable {
+
+    private static final long serialVersionUID = -247411021540729088L;
+
+    private final static Map<Status, Status> validTransitions =
+            ImmutableMap.<Status, Status>builder()
+                    .put(Status.UNKNOWN, Status.ACCEPTED)
+                    .put(Status.ACCEPTED, Status.STARTING)
+                    .put(Status.STARTING, Status.RUNNING)
+                    .put(Status.RUNNING, Status.STOPPING)
+                    .put(Status.STOPPING, Status.STOPPED)
+                    .put(Status.STOPPED, Status.STARTING)
+                    .build();
+
+    private final String id;
+    private final ApplicationSpec spec;
+    private final Status status;
+    private final Map<String, URI> links;
+
+    public ApplicationSummary(
+            @JsonProperty("id") String id,
+            @JsonProperty("spec") ApplicationSpec spec,
+            @JsonProperty("status") Status status,
+            @JsonProperty("links") Map<String, URI> links
+    ) {
+        this.id = id;
+        this.spec = checkNotNull(spec, "spec");
+        this.status = checkNotNull(status, "status");
+        this.links = (links == null) ? ImmutableMap.<String, URI>of() : ImmutableMap.copyOf(links);
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+    
+    public ApplicationSpec getSpec() {
+        return spec;
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    public ApplicationSummary transitionTo(Status newStatus) {
+        if (newStatus == Status.ERROR || validTransitions.get(status) == newStatus) {
+            return new ApplicationSummary(id, spec, newStatus, links);
+        }
+        throw new IllegalStateException("Invalid transition from '" +
+                status + "' to '" + newStatus + "'");
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ApplicationSummary that = (ApplicationSummary) o;
+
+        if (spec != null ? !spec.equals(that.spec) : that.spec != null)
+            return false;
+        if (status != that.status) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = spec != null ? spec.hashCode() : 0;
+        result = 31 * result + (status != null ? status.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Application{" +
+                "id=" + id +
+                ", spec=" + spec +
+                ", status=" + status +
+                '}';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/BrooklynFeatureSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/BrooklynFeatureSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/BrooklynFeatureSummary.java
new file mode 100644
index 0000000..3f0c95d
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/BrooklynFeatureSummary.java
@@ -0,0 +1,91 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.codehaus.jackson.annotate.JsonAnyGetter;
+import org.codehaus.jackson.annotate.JsonAnySetter;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import com.google.common.collect.Maps;
+
+public class BrooklynFeatureSummary implements Serializable {
+
+    private static final long serialVersionUID = 4595452639602650453L;
+
+    private final String name;
+    private final String symbolicName;
+    private final String version;
+    private final String lastModified;
+    private Map<String, String> additionalData = Maps.newHashMap();
+
+    public BrooklynFeatureSummary(
+                @JsonProperty("name") String name,
+                @JsonProperty("symbolicName") String symbolicName,
+                @JsonProperty("version") String version,
+                @JsonProperty("lastModified") String lastModified) {
+        this.symbolicName = checkNotNull(symbolicName, "symbolicName");
+        this.name = name;
+        this.version = version;
+        this.lastModified = lastModified;
+    }
+
+    public BrooklynFeatureSummary(String name, String symbolicName, String version, String lastModified, Map<String, String> additionalData) {
+        this(name, symbolicName, version, lastModified);
+        this.additionalData = additionalData;
+    }
+
+    @JsonIgnore
+    public Map<String, String> getAdditionalData() {
+        return additionalData;
+    }
+
+    public String getLastModified() {
+        return lastModified;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getSymbolicName() {
+        return symbolicName;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    @JsonAnyGetter
+    private Map<String, String> any() {
+        return additionalData;
+    }
+
+    @JsonAnySetter
+    private void set(String name, String value) {
+        additionalData.put(name, value);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
new file mode 100644
index 0000000..307af78
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEntitySummary.java
@@ -0,0 +1,81 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+public class CatalogEntitySummary extends CatalogItemSummary {
+
+    private static final long serialVersionUID = 1063908984191424539L;
+    
+    @JsonSerialize(include=Inclusion.NON_EMPTY)
+    private final Set<EntityConfigSummary> config;
+    
+    @JsonSerialize(include=Inclusion.NON_EMPTY)
+    private final Set<SensorSummary> sensors;
+    @JsonSerialize(include=Inclusion.NON_EMPTY)
+    private final Set<EffectorSummary> effectors;
+
+    public CatalogEntitySummary(
+            @JsonProperty("symbolicName") String symbolicName,
+            @JsonProperty("version") String version,
+            @JsonProperty("name") String name,
+            @JsonProperty("javaType") String javaType,
+            @JsonProperty("planYaml") String planYaml,
+            @JsonProperty("description") String description,
+            @JsonProperty("iconUrl") String iconUrl,
+            @JsonProperty("config") Set<EntityConfigSummary> config, 
+            @JsonProperty("sensors") Set<SensorSummary> sensors, 
+            @JsonProperty("effectors") Set<EffectorSummary> effectors,
+            @JsonProperty("deprecated") boolean deprecated,
+            @JsonProperty("links") Map<String, URI> links
+        ) {
+        super(symbolicName, version, name, javaType, planYaml, description, iconUrl, deprecated, links);
+        this.config = config;
+        this.sensors = sensors;
+        this.effectors = effectors;
+    }
+
+    public Set<EntityConfigSummary> getConfig() {
+        return config;
+    }
+    
+    public Set<SensorSummary> getSensors() {
+        return sensors;
+    }
+    
+    public Set<EffectorSummary> getEffectors() {
+        return effectors;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString()+"["+
+                "config="+getConfig()+"; " +
+                "sensors="+getSensors()+"; "+
+                "effectors="+getEffectors()+"; "+
+                "deprecated="+isDeprecated()+"]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
new file mode 100644
index 0000000..1e5bc2e
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogItemSummary.java
@@ -0,0 +1,151 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+/** variant of Catalog*ItemDto objects for JS/JSON serialization;
+ * see also, subclasses */
+@JsonIgnoreProperties(ignoreUnknown = true)
+// ignore unknown, ie properties from subclasses (entity)
+public class CatalogItemSummary implements HasId, HasName, Serializable {
+
+    private static final long serialVersionUID = -823483595879417681L;
+    
+    private final String id;
+    private final String symbolicName;
+    private final String version;
+
+    //needed for backwards compatibility only (json serializer works on fields, not getters)
+    @Deprecated
+    private final String type;
+    
+    private final String javaType;
+    
+    private final String name;
+    @JsonSerialize(include=Inclusion.NON_EMPTY)
+    private final String description;
+    @JsonSerialize(include=Inclusion.NON_EMPTY)
+    private final String iconUrl;
+    private final String planYaml;
+    private final boolean deprecated;
+    
+    private final Map<String, URI> links;
+
+    public CatalogItemSummary(
+            @JsonProperty("symbolicName") String symbolicName,
+            @JsonProperty("version") String version,
+            @JsonProperty("name") String displayName,
+            @JsonProperty("javaType") String javaType,
+            @JsonProperty("planYaml") String planYaml,
+            @JsonProperty("description") String description,
+            @JsonProperty("iconUrl") String iconUrl,
+            @JsonProperty("deprecated") boolean deprecated,
+            @JsonProperty("links") Map<String, URI> links
+            ) {
+        this.id = symbolicName + ":" + version;
+        this.symbolicName = symbolicName;
+        this.type = symbolicName;
+        this.version = version;
+        this.name = displayName;
+        this.javaType = javaType;
+        this.planYaml = planYaml;
+        this.description = description;
+        this.iconUrl = iconUrl;
+        this.links = (links == null) ? ImmutableMap.<String, URI>of() : ImmutableMap.copyOf(links);
+        this.deprecated = deprecated;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    public String getSymbolicName() {
+        return symbolicName;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public String getJavaType() {
+        return javaType;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getPlanYaml() {
+        return planYaml;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getIconUrl() {
+        return iconUrl;
+    }
+
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    public boolean isDeprecated() {
+        return deprecated;
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(this)
+                .add("id", symbolicName)
+                .add("version", version)
+                .add("deprecated", deprecated)
+                .toString();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(symbolicName, version, name, javaType, deprecated);
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.java
new file mode 100644
index 0000000..c264db8
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogLocationSummary.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.apache.brooklyn.rest.domain;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import com.google.common.collect.ImmutableSet;
+
+public class CatalogLocationSummary extends CatalogItemSummary {
+
+    private final Set<LocationConfigSummary> config;
+
+    public CatalogLocationSummary(
+            @JsonProperty("symbolicName") String symbolicName,
+            @JsonProperty("version") String version,
+            @JsonProperty("name") String name,
+            @JsonProperty("javaType") String javaType,
+            @JsonProperty("planYaml") String planYaml,
+            @JsonProperty("description") String description,
+            @JsonProperty("iconUrl") String iconUrl,
+            @JsonProperty("config") Set<LocationConfigSummary> config,
+            @JsonProperty("deprecated") boolean deprecated,
+            @JsonProperty("links") Map<String, URI> links
+        ) {
+        super(symbolicName, version, name, javaType, planYaml, description, iconUrl, deprecated, links);
+        // TODO expose config from policies
+        this.config = (config == null) ? ImmutableSet.<LocationConfigSummary>of() : config;
+    }
+    
+    public Set<LocationConfigSummary> getConfig() {
+        return config;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString()+"["+
+                "config="+getConfig()+"]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.java
new file mode 100644
index 0000000..7906558
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogPolicySummary.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.apache.brooklyn.rest.domain;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import com.google.common.collect.ImmutableSet;
+
+public class CatalogPolicySummary extends CatalogItemSummary {
+
+    private static final long serialVersionUID = -588856488327394445L;
+    
+    @JsonSerialize(include=Inclusion.NON_EMPTY)
+    private final Set<PolicyConfigSummary> config;
+
+    public CatalogPolicySummary(
+            @JsonProperty("symbolicName") String symbolicName,
+            @JsonProperty("version") String version,
+            @JsonProperty("name") String name,
+            @JsonProperty("javaType") String javaType,
+            @JsonProperty("planYaml") String planYaml,
+            @JsonProperty("description") String description,
+            @JsonProperty("iconUrl") String iconUrl,
+            @JsonProperty("config") Set<PolicyConfigSummary> config,
+            @JsonProperty("deprecated") boolean deprecated,
+            @JsonProperty("links") Map<String, URI> links
+        ) {
+        super(symbolicName, version, name, javaType, planYaml, description, iconUrl, deprecated, links);
+        // TODO expose config from policies
+        this.config = (config == null) ? ImmutableSet.<PolicyConfigSummary>of() : config;
+    }
+    
+    public Set<PolicyConfigSummary> getConfig() {
+        return config;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString()+"["+
+                "config="+getConfig()+"]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java
new file mode 100644
index 0000000..5f79e4d
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/ConfigSummary.java
@@ -0,0 +1,172 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.util.collections.Jsonya;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableMap;
+
+public abstract class ConfigSummary implements HasName, Serializable {
+
+    private static final long serialVersionUID = -2831796487073496730L;
+    
+    private final String name;
+    private final String type;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final Object defaultValue;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final String description;
+    @JsonSerialize
+    private final boolean reconfigurable;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final String label;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final Double priority;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final List<Map<String, String>> possibleValues;
+
+    protected ConfigSummary(
+            @JsonProperty("name") String name,
+            @JsonProperty("type") String type,
+            @JsonProperty("description") String description,
+            @JsonProperty("defaultValue") Object defaultValue,
+            @JsonProperty("reconfigurable") boolean reconfigurable,
+            @JsonProperty("label") String label,
+            @JsonProperty("priority") Double priority,
+            @JsonProperty("possibleValues") List<Map<String, String>> possibleValues) {
+        this.name = name;
+        this.type = type;
+        this.description = description;
+        this.defaultValue = defaultValue;
+        this.reconfigurable = reconfigurable;
+        this.label = label;
+        this.priority = priority;
+        this.possibleValues = possibleValues;
+    }
+
+    protected ConfigSummary(ConfigKey<?> config) {
+        this(config, null, null);
+    }
+
+    @SuppressWarnings("rawtypes")
+    protected ConfigSummary(ConfigKey<?> config, String label, Double priority) {
+        this.name = config.getName();
+        this.description = config.getDescription();
+        this.reconfigurable = config.isReconfigurable();
+
+        /* Use String, to guarantee it is serializable; otherwise get:
+         *   No serializer found for class brooklyn.policy.autoscaling.AutoScalerPolicy$3 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[9]->org.apache.brooklyn.rest.domain.PolicyConfigSummary["defaultValue"])
+         *   at org.codehaus.jackson.map.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:52)
+         */
+        this.label = label;
+        this.priority = priority;
+        if (config.getType().isEnum()) {
+            this.type = Enum.class.getName();
+            this.defaultValue = (config.getDefaultValue() == null) ? null : ((Enum) config.getDefaultValue()).name();
+            this.possibleValues = FluentIterable
+                    .from(Arrays.asList((Enum[])(config.getType().getEnumConstants())))
+                    .transform(new Function<Enum, Map<String, String>>() {
+                        @Nullable
+                        @Override
+                        public Map<String, String> apply(@Nullable Enum input) {
+                            return ImmutableMap.of(
+                                    "value", input != null ? input.name() : null,
+                                   "description", input != null ? input.toString() : null);
+                        }})
+                    .toList();
+        } else {
+            this.type = config.getTypeName();
+            this.defaultValue = Jsonya.convertToJsonPrimitive(config.getDefaultValue());
+            this.possibleValues = null;
+        }
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public boolean isReconfigurable() {
+        return reconfigurable;
+    }
+
+    public Object getDefaultValue() {
+        // note constructor has converted to string, so this is safe for clients to use
+        return defaultValue;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public Double getPriority() {
+        return priority;
+    }
+
+    public List<Map<String, String>> getPossibleValues() {
+        return possibleValues;
+    }
+
+    public abstract Map<String, URI> getLinks();
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ConfigSummary that = (ConfigSummary) o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        return result;
+    }
+
+    @Override
+    public abstract String toString();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java
new file mode 100644
index 0000000..9a2d4ae
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EffectorSummary.java
@@ -0,0 +1,187 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+public class EffectorSummary implements HasName, Serializable {
+
+    private static final long serialVersionUID = 8103535211378449509L;
+
+    public static class ParameterSummary<T> implements HasName, Serializable {
+        private static final long serialVersionUID = -6393686096290306153L;
+        
+        private final String name;
+        private final String type;
+        @JsonSerialize(include = Inclusion.NON_NULL)
+        private final String description;
+        private final T defaultValue;
+
+        public ParameterSummary (
+                @JsonProperty("name") String name,
+                @JsonProperty("type") String type,
+                @JsonProperty("description") String description,
+                @JsonProperty("defaultValue") T defaultValue) {
+            this.name = name;
+            this.type = type;
+            this.description = description;
+            this.defaultValue = defaultValue;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+
+        public T getDefaultValue() {
+            return defaultValue;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+    
+          ParameterSummary<?> that = (ParameterSummary<?>) o;
+    
+          return Objects.equal(this.name, that.name)
+                  && Objects.equal(this.type, that.type)
+                  && Objects.equal(this.description, that.description)
+                  && Objects.equal(this.defaultValue, that.defaultValue);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(name, type, description, defaultValue);
+        }
+
+        @Override
+        public String toString() {
+            return Objects.toStringHelper(this)
+                    .omitNullValues()
+                    .add("name", name)
+                    .add("type", type)
+                    .add("description", description)
+                    .add("defaultValue", defaultValue)
+                    .toString();
+        }
+    }
+
+    private final String name;
+    private final String returnType;
+    private final Set<ParameterSummary<?>> parameters;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final String description;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final Map<String, URI> links;
+
+    public EffectorSummary(
+            @JsonProperty("name") String name,
+            @JsonProperty("returnType") String returnType,
+            @JsonProperty("parameters") Set<ParameterSummary<?>> parameters,
+            @JsonProperty("description") String description,
+            @JsonProperty("links") Map<String, URI> links) {
+        this.name = name;
+        this.description = description;
+        this.returnType = returnType;
+        this.parameters = parameters;
+        this.links = links != null ? ImmutableMap.copyOf(links) : null;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getReturnType() {
+        return returnType;
+    }
+
+    public Set<ParameterSummary<?>> getParameters() {
+        return parameters;
+    }
+
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        EffectorSummary that = (EffectorSummary) o;
+
+        if (description != null ? !description.equals(that.description) : that.description != null)
+            return false;
+        if (links != null ? !links.equals(that.links) : that.links != null)
+            return false;
+        if (name != null ? !name.equals(that.name) : that.name != null)
+            return false;
+        if (parameters != null ? !parameters.equals(that.parameters) : that.parameters != null)
+            return false;
+        if (returnType != null ? !returnType.equals(that.returnType) : that.returnType != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (description != null ? description.hashCode() : 0);
+        result = 31 * result + (returnType != null ? returnType.hashCode() : 0);
+        result = 31 * result + (parameters != null ? parameters.hashCode() : 0);
+        result = 31 * result + (links != null ? links.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "EffectorSummary{"
+                + "name='" + name + '\''
+                + ", description='" + description + '\''
+                + ", returnType='" + returnType + '\''
+                + ", parameters=" + parameters
+                + ", links=" + links
+                + '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityConfigSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityConfigSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityConfigSummary.java
new file mode 100644
index 0000000..fb59a65
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntityConfigSummary.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.domain;
+
+import brooklyn.config.ConfigKey;
+import com.google.common.collect.ImmutableMap;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+public class EntityConfigSummary extends ConfigSummary {
+
+    private static final long serialVersionUID = -1336134336883426030L;
+    
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final Map<String, URI> links;
+
+    public EntityConfigSummary(
+            @JsonProperty("name") String name,
+            @JsonProperty("type") String type,
+            @JsonProperty("description") String description,
+            @JsonProperty("defaultValue") Object defaultValue,
+            @JsonProperty("reconfigurable") boolean reconfigurable,
+            @JsonProperty("label") String label,
+            @JsonProperty("priority") Double priority,
+            @JsonProperty("possibleValues") List<Map<String, String>> possibleValues,
+            @JsonProperty("links") Map<String, URI> links) {
+        super(name, type, description, defaultValue, reconfigurable, label, priority, possibleValues);
+        this.links = (links == null) ? ImmutableMap.<String, URI>of() : ImmutableMap.copyOf(links);
+    }
+
+    public EntityConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
+        super(config, label, priority);
+        this.links = links != null ? ImmutableMap.copyOf(links) : null;
+    }
+
+    @Override
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    @Override
+    public String toString() {
+        return "EntityConfigSummary{"
+                + "name='" + getName() + '\''
+                + ", type='" + getType() + '\''
+                + '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySpec.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySpec.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySpec.java
new file mode 100644
index 0000000..a7110a2
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySpec.java
@@ -0,0 +1,102 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+
+public class EntitySpec implements HasName, Serializable {
+
+    private static final long serialVersionUID = -3882575609132757188L;
+    
+    private final String name;
+    private final String type;
+    private final Map<String, String> config;
+
+    public EntitySpec(String type) {
+        this(null, type);
+    }
+
+    public EntitySpec(String name, String type) {
+        this(name, type, Collections.<String, String> emptyMap());
+    }
+
+    public EntitySpec(
+            @JsonProperty("name") String name,
+            @JsonProperty("type") String type,
+            @JsonProperty("config") Map<String, String> config) {
+        this.type = checkNotNull(type, "type");
+        this.name = (name == null) ? type : name;
+        this.config = (config != null) ? ImmutableMap.copyOf(config) : ImmutableMap.<String, String> of();
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public Map<String, String> getConfig() {
+        return config;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        EntitySpec entitySpec = (EntitySpec) o;
+
+        if (config != null ? !config.equals(entitySpec.config) : entitySpec.config != null)
+            return false;
+        if (name != null ? !name.equals(entitySpec.name) : entitySpec.name != null)
+            return false;
+        if (type != null ? !type.equals(entitySpec.type) : entitySpec.type != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (type != null ? type.hashCode() : 0);
+        result = 31 * result + (config != null ? config.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "EntitySpec{"
+                + "name='" + name + '\''
+                + ", type='" + type + '\''
+                + ", config=" + config
+                + '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java
new file mode 100644
index 0000000..b2bb9b1
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EntitySummary.java
@@ -0,0 +1,97 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Map;
+
+public class EntitySummary implements HasId, HasName, Serializable {
+
+    private static final long serialVersionUID = 100490507982229165L;
+    
+    private final String id;
+    private final String name;
+    private final String type;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final String catalogItemId;
+    private final Map<String, URI> links;
+
+    public EntitySummary(
+            @JsonProperty("id") String id,
+            @JsonProperty("name") String name,
+            @JsonProperty("type") String type,
+            @JsonProperty("catalogItemId") String catalogItemId,
+            @JsonProperty("links") Map<String, URI> links) {
+        this.type = type;
+        this.id = id;
+        this.name = name;
+        this.catalogItemId = catalogItemId;
+        this.links = (links == null) ? ImmutableMap.<String, URI> of() : ImmutableMap.copyOf(links);
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public String getCatalogItemId() {
+        return catalogItemId;
+    }
+
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o instanceof EntitySummary) && id.equals(((EntitySummary) o).getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return id != null ? id.hashCode() : 0;
+    }
+
+    @Override
+    public String toString() {
+        return "EntitySummary{"
+                + "id='" + id + '\''
+                + ", name=" + name
+                + ", type=" + type
+                + ", catalogItemId=" + catalogItemId
+                + ", links=" + links
+                + '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasConfig.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasConfig.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasConfig.java
new file mode 100644
index 0000000..1435242
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasConfig.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.domain;
+
+import java.util.Map;
+
+/** Marker interface for summary objects with a name field */
+public interface HasConfig {
+
+    public Map<String, ?> getConfig();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasId.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasId.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasId.java
new file mode 100644
index 0000000..69b4a9c
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasId.java
@@ -0,0 +1,26 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+/** Marker interface for summary objects with an id field */
+public interface HasId {
+
+    public String getId();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasName.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasName.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasName.java
new file mode 100644
index 0000000..962e74b
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HasName.java
@@ -0,0 +1,26 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+/** Marker interface for summary objects with a name field */
+public interface HasName {
+
+    public String getName();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HighAvailabilitySummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HighAvailabilitySummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HighAvailabilitySummary.java
new file mode 100644
index 0000000..c63d13f
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/HighAvailabilitySummary.java
@@ -0,0 +1,144 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.Map;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+public class HighAvailabilitySummary implements Serializable {
+
+    private static final long serialVersionUID = -317333127094471223L;
+
+    public static class HaNodeSummary implements Serializable {
+        private static final long serialVersionUID = 9205960988226816539L;
+        
+        private final String nodeId;
+        private final URI nodeUri;
+        private final String status;
+        private final Long localTimestamp;
+        private final Long remoteTimestamp;
+        
+        public HaNodeSummary(
+                @JsonProperty("nodeId") String nodeId,
+                @JsonProperty("nodeUri") URI nodeUri,
+                @JsonProperty("status") String status,
+                @JsonProperty("localTimestamp") Long localTimestamp,
+                @JsonProperty("remoteTimestamp") Long remoteTimestamp) {
+            this.nodeId = nodeId;
+            this.nodeUri = nodeUri;
+            this.status = status;
+            this.localTimestamp = localTimestamp;
+            this.remoteTimestamp = remoteTimestamp;
+        }
+
+        public String getNodeId() {
+            return nodeId;
+        }
+
+        public URI getNodeUri() {
+            return nodeUri;
+        }
+
+        public String getStatus() {
+            return status;
+        }
+
+        public Long getLocalTimestamp() {
+            return localTimestamp;
+        }
+
+        public Long getRemoteTimestamp() {
+            return remoteTimestamp;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return (o instanceof HaNodeSummary) && Objects.equal(nodeId, ((HaNodeSummary) o).getNodeId());
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(nodeId);
+        }
+
+        @Override
+        public String toString() {
+            return "HighAvailabilitySummary{"
+                    + "nodeId='" + nodeId + '\''
+                    + ", status='" + status + '\''
+                    + '}';
+        }
+    }
+
+    private final String ownId;
+    private final String masterId;
+    private final Map<String, HaNodeSummary> nodes;
+    private final Map<String, URI> links;
+
+    public HighAvailabilitySummary(
+            @JsonProperty("ownId") String ownId,
+            @JsonProperty("masterId") String masterId,
+            @JsonProperty("nodes") Map<String, HaNodeSummary> nodes,
+            @JsonProperty("links") Map<String, URI> links) {
+        this.ownId = ownId;
+        this.masterId = masterId;
+        this.nodes = (nodes == null) ? ImmutableMap.<String, HaNodeSummary>of() : nodes;
+        this.links = (links == null) ? ImmutableMap.<String, URI>of() : ImmutableMap.copyOf(links);
+    }
+
+    public String getOwnId() {
+        return ownId;
+    }
+
+    public String getMasterId() {
+        return masterId;
+    }
+
+    public Map<String, HaNodeSummary> getNodes() {
+        return nodes;
+    }
+
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o instanceof HighAvailabilitySummary) && ownId.equals(((HighAvailabilitySummary) o).getOwnId());
+    }
+
+    @Override
+    public int hashCode() {
+        return ownId != null ? ownId.hashCode() : 0;
+    }
+
+    @Override
+    public String toString() {
+        return "HighAvailabilitySummary{"
+                + "ownId='" + ownId + '\''
+                + ", links=" + links
+                + '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LinkWithMetadata.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LinkWithMetadata.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LinkWithMetadata.java
new file mode 100644
index 0000000..1d2af55
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LinkWithMetadata.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.apache.brooklyn.rest.domain;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableMap;
+
+@Beta
+public class LinkWithMetadata implements Serializable {
+
+    // TODO remove 'metadata' and promote its contents to be top-level fields; then unmark as Beta
+
+    private static final long serialVersionUID = 3146368899471495143L;
+    
+    private final String link;
+    private final Map<String,Object> metadata;
+    
+    public LinkWithMetadata(
+            @JsonProperty("link") String link, 
+            @Nullable @JsonProperty("metadata") Map<String,?> metadata) {
+        this.link = link;
+        this.metadata = (metadata == null) ? ImmutableMap.<String,Object>of() : ImmutableMap.<String,Object>copyOf(metadata);
+    }
+    
+    public String getLink() {
+        return link;
+    }
+    
+    public Map<String, Object> getMetadata() {
+        return metadata;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((link == null) ? 0 : link.hashCode());
+        result = prime * result + ((metadata == null) ? 0 : metadata.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        LinkWithMetadata other = (LinkWithMetadata) obj;
+        if (link == null) {
+            if (other.link != null)
+                return false;
+        } else if (!link.equals(other.link))
+            return false;
+        if (metadata == null) {
+            if (other.metadata != null)
+                return false;
+        } else if (!metadata.equals(other.metadata))
+            return false;
+        return true;
+    }
+
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationConfigSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationConfigSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationConfigSummary.java
new file mode 100644
index 0000000..2331ee7
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationConfigSummary.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.domain;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import com.google.common.collect.ImmutableMap;
+
+public class LocationConfigSummary extends ConfigSummary {
+
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final Map<String, URI> links;
+
+    public LocationConfigSummary(
+            @JsonProperty("name") String name,
+            @JsonProperty("type") String type,
+            @JsonProperty("description") String description,
+            @JsonProperty("defaultValue") Object defaultValue,
+            @JsonProperty("reconfigurable") boolean reconfigurable,
+            @JsonProperty("label") String label,
+            @JsonProperty("priority") Double priority,
+            @JsonProperty("possibleValues") List<Map<String, String>> possibleValues,
+            @JsonProperty("links") Map<String, URI> links) {
+        super(name, type, description, defaultValue, reconfigurable, label, priority, possibleValues);
+        this.links = (links == null) ? ImmutableMap.<String, URI>of() : ImmutableMap.copyOf(links);
+    }
+
+    @Override
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    @Override
+    public String toString() {
+        return "LocationConfigSummary{"
+                + "name='" + getName() + '\''
+                + ", type='" + getType() + '\''
+                + '}';
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationSpec.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationSpec.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationSpec.java
new file mode 100644
index 0000000..d6b9d41
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationSpec.java
@@ -0,0 +1,96 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+// FIXME change name, due to confusion with brooklyn.location.LocationSpec <- no need, as we can kill the class instead soon!
+/** @deprecated since 0.7.0 location spec objects will not be used from the client, instead pass yaml location spec strings */
+public class LocationSpec implements HasName, HasConfig, Serializable {
+
+    private static final long serialVersionUID = -1562824224808185255L;
+    
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final String name;
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final String spec;
+
+    @JsonSerialize(include = Inclusion.NON_EMPTY)
+    private final Map<String, ?> config;
+
+    public static LocationSpec localhost() {
+        return new LocationSpec("localhost", "localhost", null);
+    }
+
+    public LocationSpec(
+            @JsonProperty("name") String name,
+            @JsonProperty("spec") String spec,
+            @JsonProperty("config") @Nullable Map<String, ?> config) {
+        this.name = name;
+        this.spec = spec;
+        this.config = (config == null) ? Collections.<String, String> emptyMap() : ImmutableMap.copyOf(config);
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public String getSpec() {
+        return spec;
+    }
+
+    public Map<String, ?> getConfig() {
+        return config;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        LocationSpec that = (LocationSpec) o;
+        return Objects.equal(name, that.name) && Objects.equal(spec, that.spec) && Objects.equal(config, that.config);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(spec, name, config);
+    }
+
+    @Override
+    public String toString() {
+        return "LocationSpec{"
+                + "name='" + name + '\''
+                + "spec='" + spec + '\''
+                + ", config=" + config
+                + '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4c98f111/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationSummary.java b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationSummary.java
new file mode 100644
index 0000000..ec41544
--- /dev/null
+++ b/usage/rest-api/src/main/java/org/apache/brooklyn/rest/domain/LocationSummary.java
@@ -0,0 +1,96 @@
+/*
+ * 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.apache.brooklyn.rest.domain;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+public class LocationSummary extends LocationSpec implements HasName, HasId {
+
+    private static final long serialVersionUID = -4559153719273573670L;
+
+    private final String id;
+
+    /** only intended for instantiated Locations, not definitions */
+    @JsonSerialize(include = Inclusion.NON_NULL)
+    private final String type;
+    private final Map<String, URI> links;
+
+    public LocationSummary(
+            @JsonProperty("id") String id,
+            @JsonProperty("name") String name,
+            @JsonProperty("spec") String spec,
+            @JsonProperty("type") String type,
+            @JsonProperty("config") @Nullable Map<String, ?> config,
+            @JsonProperty("links") Map<String, URI> links) {
+        super(name, spec, config);
+        this.id = checkNotNull(id);
+        this.type = type;
+        this.links = (links == null) ? ImmutableMap.<String, URI> of() : ImmutableMap.copyOf(links);
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!super.equals(o)) return false;
+        LocationSummary that = (LocationSummary) o;
+        return Objects.equal(id, that.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(id, links);
+    }
+
+    @Override
+    public String toString() {
+        return "LocationSummary{"
+                + "id='" + getId() + '\''
+                + "name='" + getName() + '\''
+                + "spec='" + getSpec() + '\''
+                + "type='" + getType() + '\''
+                + ", config=" + getConfig()
+                + ", links=" + links
+                + '}';
+  }
+
+}