You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2015/04/14 15:17:49 UTC

[1/2] incubator-brooklyn git commit: Fix delete location from catalog

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 861b86a38 -> 4f6fa6ca9


Fix delete location from catalog

- On REST api (LocationResource.delete), when location is deleted
  then delete from catalog as well as from LocationRegistry.
  (Otherwise on rebind it will come back again!)
- Adds LocationApi.delete(symbolicName, version);
  Previously just had delete(id))
- Adds to CatalogApi:
   - deletePolicy
   - deleteLocation
   - listLocations
- Change CatalogApi.listEntities return type to List<CatalogEntitySummary>
  instead of List<CatalogItemSummary>
- Cleanup LocationApi: deprecated methods to do with definitions,
  preferring CatalogApi usage.
- Adds CatalogLocationSummary and LocationConfigSummary


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f114676f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f114676f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f114676f

Branch: refs/heads/master
Commit: f114676fd22b78d11ce1affa5afdbd6804b76c77
Parents: 4f1eb45
Author: Aled Sage <al...@gmail.com>
Authored: Thu Apr 2 21:07:04 2015 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Sun Apr 12 10:12:08 2015 -0500

----------------------------------------------------------------------
 .../entity/rebind/RebindCatalogItemTest.java    |  13 +-
 .../entity/rebind/RebindTestFixture.java        |   6 +
 .../main/java/brooklyn/rest/api/CatalogApi.java |  81 ++++++++++--
 .../java/brooklyn/rest/api/LocationApi.java     |  24 +++-
 .../rest/domain/CatalogLocationSummary.java     |  59 +++++++++
 .../rest/domain/LocationConfigSummary.java      |  62 +++++++++
 .../rest/resources/CatalogResource.java         | 126 +++++++++++++++++--
 .../rest/resources/LocationResource.java        |   4 +-
 .../rest/transform/CatalogTransformer.java      |  12 ++
 .../rest/resources/ApiDocResourceTest.java      |   2 +-
 .../rest/resources/CatalogResourceTest.java     |  55 +++++++-
 .../rest/resources/LocationResourceTest.java    |  98 +++++++++++----
 12 files changed, 489 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
index 5ca275a..4036dc5 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
@@ -146,7 +146,7 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
     }
 
     @Test
-    public void testAddAndRebindLocation() {
+    public void testAddAndRebindAndDeleteLocation() {
         String yaml = Joiner.on("\n").join(ImmutableList.of(
                 "name: Test Location",
                 "brooklyn.catalog:",
@@ -160,6 +160,11 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
         CatalogItem<?, ?> added = addItem(origManagementContext, yaml);
         assertEquals(added.getCatalogItemType(), CatalogItemType.LOCATION);
         rebindAndAssertCatalogsAreEqual();
+        
+        deleteItem(newManagementContext, added.getSymbolicName(), added.getVersion());
+        
+        switchOriginalToNewManagementContext();
+        rebindAndAssertCatalogsAreEqual();
     }
 
     @Test(enabled = false)
@@ -239,6 +244,12 @@ public class RebindCatalogItemTest extends RebindTestFixtureWithApp {
         return added;
     }
     
+    protected void deleteItem(ManagementContext mgmt, String symbolicName, String version) {
+        mgmt.getCatalog().deleteCatalogItem(symbolicName, version);
+        LOG.info("Deleted item from catalog: {}:{}", symbolicName, version);
+        assertCatalogDoesNotContain(mgmt.getCatalog(), symbolicName, version);
+    }
+    
     private void rebindAndAssertCatalogsAreEqual() {
         try {
             rebind();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
index b74ab74..c307aa4 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
@@ -20,6 +20,7 @@ package brooklyn.entity.rebind;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
 
 import java.io.File;
 import java.util.List;
@@ -316,4 +317,9 @@ public abstract class RebindTestFixture<T extends StartableApplication> {
         assertNotNull(found);
         assertCatalogItemsEqual(found, item);
     }
+    
+    protected void assertCatalogDoesNotContain(BrooklynCatalog catalog, String symbolicName, String version) {
+        CatalogItem<?, ?> found = catalog.getCatalogItem(symbolicName, version);
+        assertNull(found);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java b/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java
index 1a03134..bf097e2 100644
--- a/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java
+++ b/usage/rest-api/src/main/java/brooklyn/rest/api/CatalogApi.java
@@ -37,6 +37,8 @@ import javax.ws.rs.core.Response;
 import brooklyn.rest.apidoc.Apidoc;
 import brooklyn.rest.domain.CatalogEntitySummary;
 import brooklyn.rest.domain.CatalogItemSummary;
+import brooklyn.rest.domain.CatalogLocationSummary;
+import brooklyn.rest.domain.CatalogPolicySummary;
 
 import com.sun.jersey.core.header.FormDataContentDisposition;
 import com.sun.jersey.multipart.FormDataParam;
@@ -52,7 +54,7 @@ import com.wordnik.swagger.core.ApiParam;
 public interface CatalogApi {
 
     @POST
-    @ApiOperation(value = "Add a catalog item (e.g. new entity or policy type) by uploading YAML descriptor from browser using multipart/form-data",
+    @ApiOperation(value = "Add a catalog item (e.g. new type of entity, policy or location) by uploading YAML descriptor from browser using multipart/form-data",
         responseClass = "String")
     @Consumes(MediaType.MULTIPART_FORM_DATA)
     public Response createFromMultipart(
@@ -62,7 +64,7 @@ public interface CatalogApi {
 
     @Consumes
     @POST
-    @ApiOperation(value = "Add a catalog item (e.g. new entity or policy type) by uploading YAML descriptor", responseClass = "String")
+    @ApiOperation(value = "Add a catalog item (e.g. new type of entity, policy or location) by uploading YAML descriptor", responseClass = "String")
     public Response create(
             @ApiParam(name = "yaml", value = "YAML descriptor of catalog item", required = true)
             @Valid String yaml);
@@ -75,7 +77,7 @@ public interface CatalogApi {
             @ApiParam(name = "xml", value = "XML descriptor of the entire catalog to install", required = true)
             @Valid String xml);
 
-    /** @deprecated since 0.7.0 use {@link #getEntity(String, String)} */
+    /** @deprecated since 0.7.0 use {@link #deleteEntity(String, String)} */
     @Deprecated
     @DELETE
     @Path("/entities/{entityId}")
@@ -100,10 +102,36 @@ public interface CatalogApi {
         @ApiParam(name = "version", value = "The version identifier of the entity or template to delete", required = true)
         @PathParam("version") String version) throws Exception;
 
+    @DELETE
+    @Path("/policies/{policyId}/{version}")
+    @ApiOperation(value = "Deletes a specific version of an policy's definition from the catalog")
+    @ApiErrors(value = {
+        @ApiError(code = 404, reason = "Policy not found")
+    })
+    public void deletePolicy(
+        @ApiParam(name = "policyId", value = "The ID of the policy to delete", required = true)
+        @PathParam("policyId") String policyId,
+
+        @ApiParam(name = "version", value = "The version identifier of the policy to delete", required = true)
+        @PathParam("version") String version) throws Exception;
+
+    @DELETE
+    @Path("/locations/{locationId}/{version}")
+    @ApiOperation(value = "Deletes a specific version of an location's definition from the catalog")
+    @ApiErrors(value = {
+        @ApiError(code = 404, reason = "Location not found")
+    })
+    public void deleteLocation(
+        @ApiParam(name = "locationId", value = "The ID of the location to delete", required = true)
+        @PathParam("locationId") String locationId,
+
+        @ApiParam(name = "version", value = "The version identifier of the location to delete", required = true)
+        @PathParam("version") String version) throws Exception;
+
     @GET
     @Path("/entities")
     @ApiOperation(value = "List available entity types optionally matching a query", responseClass = "CatalogItemSummary", multiValueResponse = true)
-    public List<CatalogItemSummary> listEntities(
+    public List<CatalogEntitySummary> listEntities(
         @ApiParam(name = "regex", value = "Regular expression to search for")
         @QueryParam("regex") @DefaultValue("") String regex,
         @ApiParam(name = "fragment", value = "Substring case-insensitive to search for")
@@ -170,14 +198,14 @@ public interface CatalogApi {
 
     @GET
     @Path("/policies")
-    @ApiOperation(value = "List available policies optionally matching a query", responseClass = "CatalogItemSummary", multiValueResponse = true)
-    public List<CatalogItemSummary> listPolicies(
+    @ApiOperation(value = "List available policies optionally matching a query", responseClass = "CatalogPolicySummary", multiValueResponse = true)
+    public List<CatalogPolicySummary> listPolicies(
             @ApiParam(name = "regex", value = "Regular expression to search for")
             @QueryParam("regex") @DefaultValue("") String regex,
             @ApiParam(name = "fragment", value = "Substring case-insensitive to search for")
             @QueryParam("fragment") @DefaultValue("") String fragment);
     
-    /** @deprecated since 0.7.0 use {@link #getEntity(String, String)} */
+    /** @deprecated since 0.7.0 use {@link #getPolicy(String, String)} */
     @Deprecated
     @GET
     @Path("/policies/{policyId}")
@@ -201,6 +229,39 @@ public interface CatalogApi {
         @ApiParam(name = "version", value = "The version identifier of the application to retrieve", required = true)
         @PathParam("version") String version) throws Exception;
     
+    @GET
+    @Path("/locations")
+    @ApiOperation(value = "List available locations optionally matching a query", responseClass = "CatalogLocationSummary", multiValueResponse = true)
+    public List<CatalogLocationSummary> listLocations(
+            @ApiParam(name = "regex", value = "Regular expression to search for")
+            @QueryParam("regex") @DefaultValue("") String regex,
+            @ApiParam(name = "fragment", value = "Substring case-insensitive to search for")
+            @QueryParam("fragment") @DefaultValue("") String fragment);
+    
+    /** @deprecated since 0.7.0 use {@link #getLocation(String, String)} */
+    @Deprecated
+    @GET
+    @Path("/locations/{locationId}")
+    @ApiOperation(value = "Fetch a location's definition from the catalog", responseClass = "CatalogItemSummary", multiValueResponse = true)
+    @ApiErrors(value = {
+        @ApiError(code = 404, reason = "Entity not found")
+    })
+    public CatalogItemSummary getLocation(
+        @ApiParam(name = "locationId", value = "The ID of the location to retrieve", required = true)
+        @PathParam("locationId") String locationId) throws Exception;
+    
+    @GET
+    @Path("/locations/{locationId}/{version}")
+    @ApiOperation(value = "Fetch a location's definition from the catalog", responseClass = "CatalogItemSummary", multiValueResponse = true)
+    @ApiErrors(value = {
+        @ApiError(code = 404, reason = "Entity not found")
+    })
+    public CatalogItemSummary getLocation(
+        @ApiParam(name = "locationId", value = "The ID of the location to retrieve", required = true)
+        @PathParam("locationId") String locationId,
+        @ApiParam(name = "version", value = "The version identifier of the application to retrieve", required = true)
+        @PathParam("version") String version) throws Exception;
+    
     /** @deprecated since 0.7.0 use {@link #getIcon(String, String)} */
     @Deprecated
     @GET
@@ -211,7 +272,7 @@ public interface CatalogApi {
         })
     @Produces("application/image")
     public Response getIcon(
-        @ApiParam(name = "itemId", value = "ID of catalog item (application, entity, policy)")
+        @ApiParam(name = "itemId", value = "ID of catalog item (application, entity, policy, location)")
         @PathParam("itemId") @DefaultValue("") String itemId);
 
     @GET
@@ -222,10 +283,10 @@ public interface CatalogApi {
         })
     @Produces("application/image")
     public Response getIcon(
-        @ApiParam(name = "itemId", value = "ID of catalog item (application, entity, policy)", required=true)
+        @ApiParam(name = "itemId", value = "ID of catalog item (application, entity, policy, location)", required=true)
         @PathParam("itemId") String itemId,
 
-        @ApiParam(name = "version", value = "version identifier of catalog item (application, entity, policy)", required=true)
+        @ApiParam(name = "version", value = "version identifier of catalog item (application, entity, policy, location)", required=true)
         @PathParam("version") String version);
 
     @POST

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java b/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java
index 4b6e32f..a5c5207 100644
--- a/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java
+++ b/usage/rest-api/src/main/java/brooklyn/rest/api/LocationApi.java
@@ -47,10 +47,14 @@ import com.wordnik.swagger.core.ApiParam;
 @Consumes(MediaType.APPLICATION_JSON)
 public interface LocationApi {
 
+    /**
+     * @deprecated since 0.7.0; use {@link CatalogApi#listLocations(String, String)}
+     */
     @GET
-    @ApiOperation(value = "Fetch the list of locations",
+    @ApiOperation(value = "Fetch the list of location definitions",
             responseClass = "brooklyn.rest.domain.LocationSummary",
             multiValueResponse = true)
+    @Deprecated
     public List<LocationSummary> list();
 
     // this is here to support the web GUI's circles
@@ -59,9 +63,13 @@ public interface LocationApi {
     @ApiOperation(value = "Return a summary of all usage", notes="interim API, expected to change")
     public Map<String,Map<String,Object>> getLocatedLocations();
 
+    /**
+     * WARNING: behaviour will change in a future release; this will only return location instances.
+     * See {@link CatalogApi#getLocation(String, String)} for retrieving location definitions.
+     */
     @GET
     @Path("/{locationId}")
-    @ApiOperation(value = "Fetch details about a location",
+    @ApiOperation(value = "Fetch details about a location instance, or a location definition",
             responseClass = "brooklyn.rest.domain.LocationSummary",
             multiValueResponse = true)
     public LocationSummary get(
@@ -71,15 +79,23 @@ public interface LocationApi {
             @DefaultValue("false")
             @QueryParam("full") String fullConfig);
 
+    /**
+     * @deprecated since 0.7.0; use {@link CatalogApi#create(String)}
+     */
     @POST
-    @ApiOperation(value = "Create a new location", responseClass = "String")
+    @ApiOperation(value = "Create a new location definition", responseClass = "String")
+    @Deprecated
     public Response create(
             @ApiParam(name = "locationSpec", value = "Location specification object", required = true)
             @Valid LocationSpec locationSpec);
 
+    /**
+     * @deprecated since 0.7.0; use {@link CatalogApi#deleteLocation(String, String)}
+     */
     @DELETE
     @Path("/{locationId}")
-    @ApiOperation(value = "Delete a location object by id")
+    @ApiOperation(value = "Deletes a location definition by id")
+    @Deprecated
     public void delete(
             @ApiParam(value = "Location id to delete", required = true)
             @PathParam("locationId") String locationId);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogLocationSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogLocationSummary.java b/usage/rest-api/src/main/java/brooklyn/rest/domain/CatalogLocationSummary.java
new file mode 100644
index 0000000..874b848
--- /dev/null
+++ b/usage/rest-api/src/main/java/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 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/f114676f/usage/rest-api/src/main/java/brooklyn/rest/domain/LocationConfigSummary.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/domain/LocationConfigSummary.java b/usage/rest-api/src/main/java/brooklyn/rest/domain/LocationConfigSummary.java
new file mode 100644
index 0000000..b315459
--- /dev/null
+++ b/usage/rest-api/src/main/java/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 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/f114676f/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java
index 7040f13..98e5a6b 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/CatalogResource.java
@@ -35,6 +35,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.catalog.CatalogItem;
+import brooklyn.catalog.CatalogItem.CatalogItemType;
 import brooklyn.catalog.CatalogPredicates;
 import brooklyn.catalog.internal.BasicBrooklynCatalog;
 import brooklyn.catalog.internal.CatalogDto;
@@ -43,6 +44,8 @@ import brooklyn.catalog.internal.CatalogUtils;
 import brooklyn.entity.Application;
 import brooklyn.entity.Entity;
 import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.location.Location;
+import brooklyn.location.LocationSpec;
 import brooklyn.management.entitlement.Entitlements;
 import brooklyn.management.entitlement.Entitlements.StringAndArgument;
 import brooklyn.policy.Policy;
@@ -51,6 +54,8 @@ import brooklyn.rest.api.CatalogApi;
 import brooklyn.rest.domain.ApiError;
 import brooklyn.rest.domain.CatalogEntitySummary;
 import brooklyn.rest.domain.CatalogItemSummary;
+import brooklyn.rest.domain.CatalogLocationSummary;
+import brooklyn.rest.domain.CatalogPolicySummary;
 import brooklyn.rest.filter.HaHotStateRequired;
 import brooklyn.rest.transform.CatalogTransformer;
 import brooklyn.rest.util.WebResourceUtils;
@@ -69,7 +74,6 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.io.Files;
 import com.sun.jersey.core.header.FormDataContentDisposition;
-import com.wordnik.swagger.core.ApiParam;
 
 @HaHotStateRequired
 public class CatalogResource extends AbstractBrooklynRestResource implements CatalogApi {
@@ -126,6 +130,10 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
             return Response.created(URI.create("policies/" + itemId))
                     .entity(CatalogTransformer.catalogPolicySummary(brooklyn(), (CatalogItem<? extends Policy, PolicySpec<?>>) item))
                     .build();
+        case LOCATION:
+            return Response.created(URI.create("locations/" + itemId + "/" + item.getVersion()))
+                    .entity(CatalogTransformer.catalogLocationSummary(brooklyn(), (CatalogItem<? extends Location, LocationSpec<?>>) item))
+                    .build();
         default:
             throw new IllegalStateException("Unsupported catalog item type "+item.getCatalogItemType()+": "+item);
         }
@@ -152,8 +160,11 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
         }
         try {
             CatalogItem<?, ?> item = CatalogUtils.getCatalogItemOptionalVersion(mgmt(), entityId);
-            if (item==null)
+            if (item==null) {
                 throw WebResourceUtils.notFound("Entity with id '%s' not found", entityId);
+            } else if (item.getCatalogItemType() != CatalogItemType.ENTITY && item.getCatalogItemType() != CatalogItemType.TEMPLATE) {
+                throw WebResourceUtils.preconditionFailed("Item with id '%s' not an entity", entityId);
+            }
             brooklyn().getCatalog().deleteCatalogItem(item.getSymbolicName(), item.getVersion());
         } catch (NoSuchElementException e) {
             throw WebResourceUtils.notFound("Entity with id '%s' not found", entityId);
@@ -166,16 +177,55 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
             throw WebResourceUtils.unauthorized("User '%s' is not authorized to modify catalog",
                 Entitlements.getEntitlementContext().user());
         }
-        try {
-            brooklyn().getCatalog().deleteCatalogItem(entityId, version);
-        } catch (NoSuchElementException e) {
+        
+        CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(entityId, version);
+        if (item == null) {
             throw WebResourceUtils.notFound("Entity with id '%s:%s' not found", entityId, version);
+        } else if (item.getCatalogItemType() != CatalogItemType.ENTITY && item.getCatalogItemType() != CatalogItemType.TEMPLATE) {
+            throw WebResourceUtils.preconditionFailed("Item with id '%s:%s' not an entity", entityId, version);
+        } else {
+            brooklyn().getCatalog().deleteCatalogItem(item.getSymbolicName(), item.getVersion());
+        }
+    }
+
+    @Override
+    public void deletePolicy(String policyId, String version) throws Exception {
+        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(policyId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) {
+            throw WebResourceUtils.unauthorized("User '%s' is not authorized to modify catalog",
+                Entitlements.getEntitlementContext().user());
+        }
+        
+        CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(policyId, version);
+        if (item == null) {
+            throw WebResourceUtils.notFound("Policy with id '%s:%s' not found", policyId, version);
+        } else if (item.getCatalogItemType() != CatalogItemType.POLICY) {
+            throw WebResourceUtils.preconditionFailed("Item with id '%s:%s' not a policy", policyId, version);
+        } else {
+            brooklyn().getCatalog().deleteCatalogItem(item.getSymbolicName(), item.getVersion());
+        }
+    }
+
+    @Override
+    public void deleteLocation(String locationId, String version) throws Exception {
+        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(locationId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) {
+            throw WebResourceUtils.unauthorized("User '%s' is not authorized to modify catalog",
+                Entitlements.getEntitlementContext().user());
+        }
+        
+        CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem(locationId, version);
+        if (item == null) {
+            throw WebResourceUtils.notFound("Location with id '%s:%s' not found", locationId, version);
+        } else if (item.getCatalogItemType() != CatalogItemType.LOCATION) {
+            throw WebResourceUtils.preconditionFailed("Item with id '%s:%s' not a location", locationId, version);
+        } else {
+            brooklyn().getCatalog().deleteCatalogItem(item.getSymbolicName(), item.getVersion());
         }
     }
 
     @Override
-    public List<CatalogItemSummary> listEntities(String regex, String fragment) {
-        return getCatalogItemSummariesMatchingRegexFragment(CatalogPredicates.IS_ENTITY, regex, fragment);
+    public List<CatalogEntitySummary> listEntities(String regex, String fragment) {
+        List<CatalogItemSummary> result = getCatalogItemSummariesMatchingRegexFragment(CatalogPredicates.IS_ENTITY, regex, fragment);
+        return cast(result, CatalogEntitySummary.class);
     }
 
     @Override
@@ -236,13 +286,14 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
-    public List<CatalogItemSummary> listPolicies(String regex, String fragment) {
-        return getCatalogItemSummariesMatchingRegexFragment(CatalogPredicates.IS_POLICY, regex, fragment);
+    public List<CatalogPolicySummary> listPolicies(String regex, String fragment) {
+        List<CatalogItemSummary> result = getCatalogItemSummariesMatchingRegexFragment(CatalogPredicates.IS_POLICY, regex, fragment);
+        return cast(result, CatalogPolicySummary.class);
     }
-    
+
     @Override
     @Deprecated
-    public CatalogItemSummary getPolicy(String policyId) {
+    public CatalogPolicySummary getPolicy(String policyId) {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, policyId)) {
             throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry",
                 Entitlements.getEntitlementContext().user());
@@ -259,7 +310,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
     }
 
     @Override
-    public CatalogItemSummary getPolicy(String policyId, String version) throws Exception {
+    public CatalogPolicySummary getPolicy(String policyId, String version) throws Exception {
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, policyId+(Strings.isBlank(version)?"":":"+version))) {
             throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry",
                 Entitlements.getEntitlementContext().user());
@@ -276,6 +327,48 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
         return CatalogTransformer.catalogPolicySummary(brooklyn(), result);
     }
 
+    @Override
+    public List<CatalogLocationSummary> listLocations(String regex, String fragment) {
+        List<CatalogItemSummary> result = getCatalogItemSummariesMatchingRegexFragment(CatalogPredicates.IS_LOCATION, regex, fragment);
+        return cast(result, CatalogLocationSummary.class);
+    }
+
+    @Override
+    @Deprecated
+    public CatalogLocationSummary getLocation(String locationId) {
+        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, locationId)) {
+            throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry",
+                Entitlements.getEntitlementContext().user());
+        }
+
+        CatalogItem<? extends Location, LocationSpec<?>> result =
+            CatalogUtils.getCatalogItemOptionalVersion(mgmt(), Location.class, locationId);
+
+        if (result==null) {
+            throw WebResourceUtils.notFound("Location with id '%s' not found", locationId);
+        }
+
+        return CatalogTransformer.catalogLocationSummary(brooklyn(), result);
+    }
+
+    @Override
+    public CatalogLocationSummary getLocation(String locationId, String version) throws Exception {
+        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, locationId+(Strings.isBlank(version)?"":":"+version))) {
+            throw WebResourceUtils.unauthorized("User '%s' is not authorized to see catalog entry",
+                Entitlements.getEntitlementContext().user());
+        }
+
+        @SuppressWarnings("unchecked")
+        CatalogItem<? extends Location, LocationSpec<?>> result =
+                (CatalogItem<? extends Location, LocationSpec<?>>)brooklyn().getCatalog().getCatalogItem(locationId, version);
+
+        if (result==null) {
+          throw WebResourceUtils.notFound("Location with id '%s:%s' not found", locationId, version);
+        }
+
+        return CatalogTransformer.catalogLocationSummary(brooklyn(), result);
+    }
+
     @SuppressWarnings({ "unchecked", "rawtypes" })
     private <T,SpecT> List<CatalogItemSummary> getCatalogItemSummariesMatchingRegexFragment(Predicate<CatalogItem<T,SpecT>> type, String regex, String fragment) {
         List filters = new ArrayList();
@@ -369,4 +462,13 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
         return Response.temporaryRedirect(URI.create(url)).build();
     }
 
+    // TODO Move to an appropriate utility class?
+    @SuppressWarnings("unchecked")
+    private static <T> List<T> cast(List<? super T> list, Class<T> elementType) {
+        List<T> result = Lists.newArrayList();
+        for (Object element : list) {
+            result.add((T) element);
+        }
+        return result;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/usage/rest-server/src/main/java/brooklyn/rest/resources/LocationResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/LocationResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/LocationResource.java
index 8d7e3f6..362d152 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/LocationResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/LocationResource.java
@@ -149,7 +149,9 @@ public class LocationResource extends AbstractBrooklynRestResource implements Lo
                   .build();
     }
 
+    @Override
+    @Deprecated
     public void delete(String locationId) {
-        brooklyn().getLocationRegistry().removeDefinedLocation(locationId);
+        brooklyn().getCatalog().deleteCatalogItem(locationId);
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java b/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
index 7222141..adee3e2 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
@@ -33,13 +33,17 @@ import brooklyn.entity.EntityType;
 import brooklyn.entity.basic.EntityDynamicType;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.event.Sensor;
+import brooklyn.location.Location;
+import brooklyn.location.LocationSpec;
 import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
 import brooklyn.rest.domain.CatalogEntitySummary;
 import brooklyn.rest.domain.CatalogItemSummary;
+import brooklyn.rest.domain.CatalogLocationSummary;
 import brooklyn.rest.domain.CatalogPolicySummary;
 import brooklyn.rest.domain.EffectorSummary;
 import brooklyn.rest.domain.EntityConfigSummary;
+import brooklyn.rest.domain.LocationConfigSummary;
 import brooklyn.rest.domain.PolicyConfigSummary;
 import brooklyn.rest.domain.SensorSummary;
 import brooklyn.rest.domain.SummaryComparators;
@@ -91,6 +95,14 @@ public class CatalogTransformer {
                 item.isDeprecated(), makeLinks(item));
     }
 
+    public static CatalogLocationSummary catalogLocationSummary(BrooklynRestResourceUtils b, CatalogItem<? extends Location,LocationSpec<?>> item) {
+        Set<LocationConfigSummary> config = ImmutableSet.of();
+        return new CatalogLocationSummary(item.getSymbolicName(), item.getVersion(), item.getDisplayName(),
+                item.getJavaType(), item.getPlanYaml(),
+                item.getDescription(), tidyIconLink(b, item, item.getIconUrl()), config,
+                item.isDeprecated(), makeLinks(item));
+    }
+
     protected static Map<String, URI> makeLinks(CatalogItem<?,?> item) {
         return MutableMap.<String, URI>of();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/usage/rest-server/src/test/java/brooklyn/rest/resources/ApiDocResourceTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/brooklyn/rest/resources/ApiDocResourceTest.java b/usage/rest-server/src/test/java/brooklyn/rest/resources/ApiDocResourceTest.java
index e58b237..bbd96a3 100644
--- a/usage/rest-server/src/test/java/brooklyn/rest/resources/ApiDocResourceTest.java
+++ b/usage/rest-server/src/test/java/brooklyn/rest/resources/ApiDocResourceTest.java
@@ -98,7 +98,7 @@ public class ApiDocResourceTest extends BrooklynRestResourceTest {
     @Test
     public void testCatalogDetails() throws Exception {
         ApidocRoot response = client().resource("/v1/apidoc/brooklyn.rest.resources.CatalogResource").get(ApidocRoot.class);
-        assertEquals(countOperations(response), 16, "ops="+getOperations(response));
+        assertEquals(countOperations(response), 21, "ops="+getOperations(response));
     }
 
     @SuppressWarnings("rawtypes")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java b/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java
index 98b20c3..eb8b848 100644
--- a/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java
+++ b/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java
@@ -32,7 +32,6 @@ import java.util.Set;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
-import brooklyn.test.TestResourceUnavailableException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -47,9 +46,12 @@ import brooklyn.management.osgi.OsgiStandaloneTest;
 import brooklyn.policy.autoscaling.AutoScalerPolicy;
 import brooklyn.rest.domain.CatalogEntitySummary;
 import brooklyn.rest.domain.CatalogItemSummary;
+import brooklyn.rest.domain.CatalogLocationSummary;
 import brooklyn.rest.domain.CatalogPolicySummary;
 import brooklyn.rest.testing.BrooklynRestResourceTest;
+import brooklyn.test.TestResourceUnavailableException;
 
+import com.google.common.base.Joiner;
 import com.google.common.collect.Iterables;
 import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.GenericType;
@@ -259,6 +261,57 @@ public class CatalogResourceTest extends BrooklynRestResourceTest {
     }
 
     @Test
+    public void testLocationAddGetAndRemove() {
+        String symbolicName = "my.catalog.location.id";
+        String locationType = "localhost";
+        String yaml = Joiner.on("\n").join(
+                "brooklyn.catalog:",
+                "  id: " + symbolicName,
+                "  name: My Catalog Location",
+                "  description: My description",
+                "  version: " + TEST_VERSION,
+                "",
+                "brooklyn.locations:",
+                "- type: " + locationType);
+
+        // Create location item
+        CatalogLocationSummary locationItem = client().resource("/v1/catalog")
+                .post(CatalogLocationSummary.class, yaml);
+
+        Assert.assertNotNull(locationItem.getPlanYaml());
+        Assert.assertTrue(locationItem.getPlanYaml().contains(locationType));
+        assertEquals(locationItem.getId(), ver(symbolicName));
+        assertEquals(locationItem.getSymbolicName(), symbolicName);
+        assertEquals(locationItem.getVersion(), TEST_VERSION);
+
+        // Retrieve location item
+        CatalogLocationSummary location = client().resource("/v1/catalog/locations/"+symbolicName+"/"+TEST_VERSION)
+                .get(CatalogLocationSummary.class);
+        assertEquals(location.getSymbolicName(), symbolicName);
+
+        // Retrieve all locations
+        Set<CatalogLocationSummary> locations = client().resource("/v1/catalog/locations")
+                .get(new GenericType<Set<CatalogLocationSummary>>() {});
+        boolean found = false;
+        for (CatalogLocationSummary contender : locations) {
+            if (contender.getSymbolicName().equals(symbolicName)) {
+                found = true;
+                break;
+            }
+        }
+        Assert.assertTrue(found, "contenders="+locations);
+        
+        // Delete
+        ClientResponse deleteResponse = client().resource("/v1/catalog/locations/"+symbolicName+"/"+TEST_VERSION)
+                .delete(ClientResponse.class);
+        assertEquals(deleteResponse.getStatus(), Response.Status.NO_CONTENT.getStatusCode());
+
+        ClientResponse getPostDeleteResponse = client().resource("/v1/catalog/locations/"+symbolicName+"/"+TEST_VERSION)
+                .get(ClientResponse.class);
+        assertEquals(getPostDeleteResponse.getStatus(), Response.Status.NOT_FOUND.getStatusCode());
+    }
+
+    @Test
     public void testDeleteCustomEntityFromCatalog() {
         String symbolicName = "my.catalog.app.id.to.subsequently.delete";
         String yaml =

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f114676f/usage/rest-server/src/test/java/brooklyn/rest/resources/LocationResourceTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/brooklyn/rest/resources/LocationResourceTest.java b/usage/rest-server/src/test/java/brooklyn/rest/resources/LocationResourceTest.java
index 5ccf591..aab0a43 100644
--- a/usage/rest-server/src/test/java/brooklyn/rest/resources/LocationResourceTest.java
+++ b/usage/rest-server/src/test/java/brooklyn/rest/resources/LocationResourceTest.java
@@ -18,8 +18,8 @@
  */
 package brooklyn.rest.resources;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.is;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
 
 import java.net.URI;
 import java.util.Map;
@@ -35,12 +35,15 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import brooklyn.location.jclouds.JcloudsLocation;
+import brooklyn.rest.domain.CatalogLocationSummary;
 import brooklyn.rest.domain.LocationSpec;
 import brooklyn.rest.domain.LocationSummary;
 import brooklyn.rest.testing.BrooklynRestResourceTest;
 import brooklyn.test.Asserts;
 
+import com.google.api.client.repackaged.com.google.common.base.Joiner;
 import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.sun.jersey.api.client.ClientResponse;
@@ -50,62 +53,111 @@ import com.sun.jersey.api.client.GenericType;
 public class LocationResourceTest extends BrooklynRestResourceTest {
 
     private static final Logger log = LoggerFactory.getLogger(LocationResourceTest.class);
-    private URI addedLocationUri;
+    private String legacyLocationName = "my-jungle-legacy";
+    private String legacyLocationVersion = "0.0.0.SNAPSHOT";
+    
+    private String locationName = "my-jungle";
+    private String locationVersion = "0.1.2";
     
     @Test
-    public void testAddNewLocation() {
+    @Deprecated
+    public void testAddLegacyLocationDefinition() {
         Map<String, String> expectedConfig = ImmutableMap.of(
                 "identity", "bob",
                 "credential", "CR3dential");
         ClientResponse response = client().resource("/v1/locations")
                 .type(MediaType.APPLICATION_JSON_TYPE)
-                .post(ClientResponse.class, new LocationSpec("my-jungle", "aws-ec2:us-east-1", expectedConfig));
+                .post(ClientResponse.class, new LocationSpec(legacyLocationName, "aws-ec2:us-east-1", expectedConfig));
 
-        addedLocationUri = response.getLocation();
-        log.info("added, at: " + addedLocationUri);
+        URI addedLegacyLocationUri = response.getLocation();
+        log.info("added legacy, at: " + addedLegacyLocationUri);
         LocationSummary location = client().resource(response.getLocation()).get(LocationSummary.class);
         log.info(" contents: " + location);
-        Assert.assertEquals(location.getSpec(), "brooklyn.catalog:my-jungle:0.0.0.SNAPSHOT");
-        Assert.assertTrue(addedLocationUri.toString().startsWith("/v1/locations/"));
+        assertEquals(location.getSpec(), "brooklyn.catalog:"+legacyLocationName+":"+legacyLocationVersion);
+        assertTrue(addedLegacyLocationUri.toString().startsWith("/v1/locations/"));
+
+        JcloudsLocation l = (JcloudsLocation) getManagementContext().getLocationRegistry().resolve(legacyLocationName);
+        Assert.assertEquals(l.getProvider(), "aws-ec2");
+        Assert.assertEquals(l.getRegion(), "us-east-1");
+        Assert.assertEquals(l.getIdentity(), "bob");
+        Assert.assertEquals(l.getCredential(), "CR3dential");
+    }
+
+    @Test
+    public void testAddNewLocationDefinition() {
+        String yaml = Joiner.on("\n").join(ImmutableList.of(
+                "brooklyn.catalog:",
+                "  symbolicName: "+locationName,
+                "  version: " + locationVersion,
+                "",
+                "brooklyn.locations:",
+                "- type: "+"aws-ec2:us-east-1",
+                "  brooklyn.config:",
+                "    identity: bob",
+                "    credential: CR3dential"));
+
+        
+        ClientResponse response = client().resource("/v1/catalog")
+                .post(ClientResponse.class, yaml);
+
+        assertEquals(response.getStatus(), Response.Status.CREATED.getStatusCode());
+        
+
+        URI addedCatalogItemUri = response.getLocation();
+        log.info("added, at: " + addedCatalogItemUri);
+        
+        // Ensure location definition exists
+        CatalogLocationSummary locationItem = client().resource("/v1/catalog/locations/"+locationName + "/" + locationVersion)
+                .get(CatalogLocationSummary.class);
+        log.info(" item: " + locationItem);
+        LocationSummary locationSummary = client().resource(URI.create("/v1/locations/"+locationName+"/")).get(LocationSummary.class);
+        log.info(" summary: " + locationSummary);
+        Assert.assertEquals(locationSummary.getSpec(), "brooklyn.catalog:"+locationName+":"+locationVersion);
 
-        JcloudsLocation l = (JcloudsLocation) getManagementContext().getLocationRegistry().resolve("my-jungle");
+        // Ensure location is usable - can instantiate, and has right config
+        JcloudsLocation l = (JcloudsLocation) getManagementContext().getLocationRegistry().resolve(locationName);
         Assert.assertEquals(l.getProvider(), "aws-ec2");
         Assert.assertEquals(l.getRegion(), "us-east-1");
         Assert.assertEquals(l.getIdentity(), "bob");
         Assert.assertEquals(l.getCredential(), "CR3dential");
     }
 
-    @Test(dependsOnMethods = { "testAddNewLocation" })
-    public void testListAllLocations() {
+    @Test(dependsOnMethods = { "testAddNewLocationDefinition" })
+    public void testListAllLocationDefinitions() {
         Set<LocationSummary> locations = client().resource("/v1/locations")
                 .get(new GenericType<Set<LocationSummary>>() {});
         Iterable<LocationSummary> matching = Iterables.filter(locations, new Predicate<LocationSummary>() {
             @Override
             public boolean apply(@Nullable LocationSummary l) {
-                return "my-jungle".equals(l.getName());
+                return locationName.equals(l.getName());
             }
         });
         LocationSummary location = Iterables.getOnlyElement(matching);
-        assertThat(location.getSpec(), is("brooklyn.catalog:my-jungle:0.0.0.SNAPSHOT"));
-        Assert.assertEquals(location.getLinks().get("self"), addedLocationUri);
+        
+        URI expectedLocationUri = URI.create("/v1/locations/"+locationName);
+        Assert.assertEquals(location.getSpec(), "brooklyn.catalog:"+locationName+":"+locationVersion);
+        Assert.assertEquals(location.getLinks().get("self"), expectedLocationUri);
     }
 
-    @Test(dependsOnMethods = { "testListAllLocations" })
-    public void testGetASpecificLocation() {
-        LocationSummary location = client().resource(addedLocationUri.toString()).get(LocationSummary.class);
-        assertThat(location.getSpec(), is("brooklyn.catalog:my-jungle:0.0.0.SNAPSHOT"));
+    @Test(dependsOnMethods = { "testListAllLocationDefinitions" })
+    public void testGetSpecificLocation() {
+        URI expectedLocationUri = URI.create("/v1/locations/"+locationName);
+        LocationSummary location = client().resource(expectedLocationUri).get(LocationSummary.class);
+        assertEquals(location.getSpec(), "brooklyn.catalog:"+locationName+":"+locationVersion);
     }
 
-    @Test(dependsOnMethods = { "testGetASpecificLocation" })
+    @Test(dependsOnMethods = { "testAddLegacyLocationDefinition" })
+    @Deprecated
     public void testDeleteLocation() {
         final int size = getLocationRegistry().getDefinedLocations().size();
+        URI expectedLocationUri = URI.create("/v1/locations/"+legacyLocationName);
 
-        ClientResponse response = client().resource(addedLocationUri).delete(ClientResponse.class);
-        assertThat(response.getStatus(), is(Response.Status.NO_CONTENT.getStatusCode()));
+        ClientResponse response = client().resource(expectedLocationUri).delete(ClientResponse.class);
+        assertEquals(response.getStatus(), Response.Status.NO_CONTENT.getStatusCode());
         Asserts.succeedsEventually(new Runnable() {
             @Override
             public void run() {
-                assertThat(getLocationRegistry().getDefinedLocations().size(), is(size - 1));
+                assertEquals(getLocationRegistry().getDefinedLocations().size(), size - 1);
             }
         });
     }


[2/2] incubator-brooklyn git commit: This closes #593

Posted by al...@apache.org.
This closes #593


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/4f6fa6ca
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/4f6fa6ca
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/4f6fa6ca

Branch: refs/heads/master
Commit: 4f6fa6ca9199431a328704adf3d22f31cf0c28d8
Parents: 861b86a f114676
Author: Aled Sage <al...@gmail.com>
Authored: Tue Apr 14 08:17:27 2015 -0500
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Apr 14 08:17:27 2015 -0500

----------------------------------------------------------------------
 .../entity/rebind/RebindCatalogItemTest.java    |  13 +-
 .../entity/rebind/RebindTestFixture.java        |   6 +
 .../main/java/brooklyn/rest/api/CatalogApi.java |  81 ++++++++++--
 .../java/brooklyn/rest/api/LocationApi.java     |  24 +++-
 .../rest/domain/CatalogLocationSummary.java     |  59 +++++++++
 .../rest/domain/LocationConfigSummary.java      |  62 +++++++++
 .../rest/resources/CatalogResource.java         | 126 +++++++++++++++++--
 .../rest/resources/LocationResource.java        |   4 +-
 .../rest/transform/CatalogTransformer.java      |  12 ++
 .../rest/resources/ApiDocResourceTest.java      |   2 +-
 .../rest/resources/CatalogResourceTest.java     |  55 +++++++-
 .../rest/resources/LocationResourceTest.java    |  98 +++++++++++----
 12 files changed, 489 insertions(+), 53 deletions(-)
----------------------------------------------------------------------