You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by dr...@apache.org on 2017/04/14 12:11:00 UTC

[1/4] brooklyn-server git commit: Allow passing "latest" as version for catalog endpoint

Repository: brooklyn-server
Updated Branches:
  refs/heads/master c80e38969 -> a069cc533


Allow passing "latest" as version for catalog endpoint


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

Branch: refs/heads/master
Commit: 7ba584cc249fff1dc138a6e2d8cdf7e81c042578
Parents: 1772845
Author: Thomas Bouron <th...@cloudsoftcorp.com>
Authored: Thu Apr 13 08:11:52 2017 +0100
Committer: Thomas Bouron <th...@cloudsoftcorp.com>
Committed: Thu Apr 13 18:14:19 2017 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/rest/api/CatalogApi.java    | 49 ++++++++++++++++----
 .../rest/resources/CatalogResource.java         | 29 ++++++++++++
 2 files changed, 69 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7ba584cc/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
index a95aa9f..dd50bed 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
@@ -153,7 +153,11 @@ public interface CatalogApi {
 
     @DELETE
     @Path("/applications/{symbolicName}/{version}")
-    @ApiOperation(value = "Deletes a specific version of an application's definition from the catalog")
+    @ApiOperation(
+            value = "Deletes a specific version of an application's definition from the catalog",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'symbolicName'"
+    )
     @ApiResponses(value = {
         @ApiResponse(code = 404, message = "Entity not found")
     })
@@ -166,7 +170,11 @@ public interface CatalogApi {
 
     @DELETE
     @Path("/entities/{symbolicName}/{version}")
-    @ApiOperation(value = "Deletes a specific version of an entity's definition from the catalog")
+    @ApiOperation(
+            value = "Deletes a specific version of an entity's definition from the catalog",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'symbolicName'"
+    )
     @ApiResponses(value = {
         @ApiResponse(code = 404, message = "Entity not found")
     })
@@ -179,7 +187,10 @@ public interface CatalogApi {
 
     @DELETE
     @Path("/policies/{policyId}/{version}")
-    @ApiOperation(value = "Deletes a specific version of an policy's definition from the catalog")
+    @ApiOperation(
+            value = "Deletes a specific version of an policy's definition from the catalog",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'policyId'")
     @ApiResponses(value = {
         @ApiResponse(code = 404, message = "Policy not found")
     })
@@ -192,7 +203,11 @@ public interface CatalogApi {
 
     @DELETE
     @Path("/locations/{locationId}/{version}")
-    @ApiOperation(value = "Deletes a specific version of an location's definition from the catalog")
+    @ApiOperation(
+            value = "Deletes a specific version of an location's definition from the catalog",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'locationId'"
+    )
     @ApiResponses(value = {
         @ApiResponse(code = 404, message = "Location not found")
     })
@@ -245,7 +260,10 @@ public interface CatalogApi {
 
     @GET
     @Path("/entities/{symbolicName}/{version}")
-    @ApiOperation(value = "Fetch a specific version of an entity's definition from the catalog", 
+    @ApiOperation(
+            value = "Fetch a specific version of an entity's definition from the catalog",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'symbolicName'",
             response = CatalogEntitySummary.class,
             responseContainer = "List")
     @ApiResponses(value = {
@@ -274,7 +292,10 @@ public interface CatalogApi {
 
     @GET
     @Path("/applications/{symbolicName}/{version}")
-    @ApiOperation(value = "Fetch a specific version of an application's definition from the catalog", 
+    @ApiOperation(
+            value = "Fetch a specific version of an application's definition from the catalog",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'symbolicName'",
             response = CatalogEntitySummary.class,
             responseContainer = "List")
     @ApiResponses(value = {
@@ -316,7 +337,10 @@ public interface CatalogApi {
 
     @GET
     @Path("/policies/{policyId}/{version}")
-    @ApiOperation(value = "Fetch a policy's definition from the catalog", 
+    @ApiOperation(
+            value = "Fetch a policy's definition from the catalog",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'policyId'",
             response = CatalogItemSummary.class,
             responseContainer = "List")
     @ApiResponses(value = {
@@ -357,7 +381,10 @@ public interface CatalogApi {
 
     @GET
     @Path("/locations/{locationId}/{version}")
-    @ApiOperation(value = "Fetch a location's definition from the catalog", 
+    @ApiOperation(
+            value = "Fetch a location's definition from the catalog",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'locationId'",
             response = CatalogItemSummary.class,
             responseContainer = "List")
     @ApiResponses(value = {
@@ -384,7 +411,11 @@ public interface CatalogApi {
 
     @GET
     @Path("/icon/{itemId}/{version}")
-    @ApiOperation(value = "Return the icon for a given catalog entry (application/image or HTTP redirect)")
+    @ApiOperation(
+            value = "Return the icon for a given catalog entry (application/image or HTTP redirect)",
+            notes = "Version must exists, otherwise the API will return a 404. Alternatively, passing 'latest' will" +
+                    "pick up the latest version for the given 'itemId'"
+    )
     @ApiResponses(value = {
             @ApiResponse(code = 404, message = "Item not found")
         })

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7ba584cc/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
index 1421bd1..713cdb9 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
@@ -102,6 +102,7 @@ import com.google.common.io.Files;
 public class CatalogResource extends AbstractBrooklynRestResource implements CatalogApi {
 
     private static final Logger log = LoggerFactory.getLogger(CatalogResource.class);
+    private static final String LATEST = "latest";
     
     @SuppressWarnings("rawtypes")
     private Function<CatalogItem, CatalogItemSummary> toCatalogItemSummary(final UriInfo ui) {
@@ -331,6 +332,10 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
                 Entitlements.getEntitlementContext().user());
         }
+
+        if (LATEST.equals(version)) {
+            version = null;
+        }
         
         RegisteredType item = mgmt().getTypeRegistry().get(symbolicName, version);
         if (item == null) {
@@ -348,6 +353,10 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
                 Entitlements.getEntitlementContext().user());
         }
+
+        if (LATEST.equals(version)) {
+            version = null;
+        }
         
         RegisteredType item = mgmt().getTypeRegistry().get(policyId, version);
         if (item == null) {
@@ -365,6 +374,10 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
             throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
                 Entitlements.getEntitlementContext().user());
         }
+
+        if (LATEST.equals(version)) {
+            version = null;
+        }
         
         RegisteredType item = mgmt().getTypeRegistry().get(locationId, version);
         if (item == null) {
@@ -422,6 +435,10 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
+        if (LATEST.equals(version)) {
+            version = null;
+        }
+
         //TODO These casts are not pretty, we could just provide separate get methods for the different types?
         //Or we could provide asEntity/asPolicy cast methods on the CataloItem doing a safety check internally
         @SuppressWarnings("unchecked")
@@ -481,6 +498,10 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
+        if (LATEST.equals(version)) {
+            version = null;
+        }
+
         @SuppressWarnings("unchecked")
         CatalogItem<? extends Policy, PolicySpec<?>> result =
                 (CatalogItem<? extends Policy, PolicySpec<?>>)brooklyn().getCatalog().getCatalogItem(policyId, version);
@@ -527,6 +548,10 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
+        if (LATEST.equals(version)) {
+            version = null;
+        }
+
         @SuppressWarnings("unchecked")
         CatalogItem<? extends Location, LocationSpec<?>> result =
                 (CatalogItem<? extends Location, LocationSpec<?>>)brooklyn().getCatalog().getCatalogItem(locationId, version);
@@ -575,6 +600,10 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
             throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry",
                 Entitlements.getEntitlementContext().user());
         }
+
+        if (LATEST.equals(version)) {
+            version = null;
+        }
         
         return getCatalogItemIcon(mgmt().getTypeRegistry().get(itemId, version));
     }


[3/4] brooklyn-server git commit: Make the version process case-insensitive and add test for it

Posted by dr...@apache.org.
Make the version process case-insensitive and add test for it


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

Branch: refs/heads/master
Commit: 361a0fd47377d012d8b484dc925b4da3695887d3
Parents: 6ad3b5c
Author: Thomas Bouron <th...@cloudsoftcorp.com>
Authored: Fri Apr 14 10:50:12 2017 +0100
Committer: Thomas Bouron <th...@cloudsoftcorp.com>
Committed: Fri Apr 14 10:50:12 2017 +0100

----------------------------------------------------------------------
 .../rest/resources/CatalogResource.java         | 35 ++++++--------
 .../rest/resources/CatalogResourceTest.java     | 49 +++++++++-----------
 2 files changed, 35 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/361a0fd4/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
index 713cdb9..bc75ce5 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
@@ -114,6 +114,13 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
         };
     };
 
+    private String processVersion(String version) {
+        if (version != null && LATEST.equals(version.toLowerCase())) {
+            version = null;
+        }
+        return version;
+    }
+
     static Set<String> missingIcons = MutableSet.of();
 
     @Override
@@ -333,9 +340,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
-        if (LATEST.equals(version)) {
-            version = null;
-        }
+        version = processVersion(version);
         
         RegisteredType item = mgmt().getTypeRegistry().get(symbolicName, version);
         if (item == null) {
@@ -354,9 +359,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
-        if (LATEST.equals(version)) {
-            version = null;
-        }
+        version = processVersion(version);
         
         RegisteredType item = mgmt().getTypeRegistry().get(policyId, version);
         if (item == null) {
@@ -375,9 +378,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
-        if (LATEST.equals(version)) {
-            version = null;
-        }
+        version = processVersion(version);
         
         RegisteredType item = mgmt().getTypeRegistry().get(locationId, version);
         if (item == null) {
@@ -435,9 +436,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
-        if (LATEST.equals(version)) {
-            version = null;
-        }
+        version = processVersion(version);
 
         //TODO These casts are not pretty, we could just provide separate get methods for the different types?
         //Or we could provide asEntity/asPolicy cast methods on the CataloItem doing a safety check internally
@@ -498,9 +497,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
-        if (LATEST.equals(version)) {
-            version = null;
-        }
+        version = processVersion(version);
 
         @SuppressWarnings("unchecked")
         CatalogItem<? extends Policy, PolicySpec<?>> result =
@@ -548,9 +545,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
-        if (LATEST.equals(version)) {
-            version = null;
-        }
+        version = processVersion(version);
 
         @SuppressWarnings("unchecked")
         CatalogItem<? extends Location, LocationSpec<?>> result =
@@ -601,9 +596,7 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                 Entitlements.getEntitlementContext().user());
         }
 
-        if (LATEST.equals(version)) {
-            version = null;
-        }
+        version = processVersion(version);
         
         return getCatalogItemIcon(mgmt().getTypeRegistry().get(itemId, version));
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/361a0fd4/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java
index ac2d2d9..500508e 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java
@@ -890,6 +890,19 @@ public class CatalogResourceTest extends BrooklynRestResourceTest {
         assertEquals(application.getVersion(), TEST_LASTEST_VERSION);
     }
 
+    @Test(dependsOnMethods = {"testGetOnlyLatestApplication"})
+    public void testGetOnlyLatestDifferentCases() {
+        String symbolicName = "latest.catalog.application.id";
+
+        CatalogItemSummary application = client().path("/catalog/applications/" + symbolicName + "/LaTeSt")
+                .get(CatalogItemSummary.class);
+        assertEquals(application.getVersion(), TEST_LASTEST_VERSION);
+
+        application = client().path("/catalog/applications/" + symbolicName + "/LATEST")
+                .get(CatalogItemSummary.class);
+        assertEquals(application.getVersion(), TEST_LASTEST_VERSION);
+    }
+
     @Test
     public void testGetOnlyLatestEntity() {
         String symbolicName = "latest.catalog.entity.id";
@@ -932,14 +945,9 @@ public class CatalogResourceTest extends BrooklynRestResourceTest {
         assertEquals(application.getVersion(), TEST_LASTEST_VERSION);
     }
 
-    @Test
+    @Test(dependsOnMethods = {"testGetOnlyLatestApplication", "testGetOnlyLatestDifferentCases"})
     public void testDeleteOnlyLatestApplication() throws IOException {
-        String symbolicName = "latest.catalog.application.delete.id";
-        String itemType = "template";
-        String serviceType = "org.apache.brooklyn.core.test.entity.TestEntity";
-
-        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
-        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+        String symbolicName = "latest.catalog.application.id";
 
         Response deleteResponse = client().path("/catalog/applications/" + symbolicName + "/latest").delete();
         assertEquals(deleteResponse.getStatus(), HttpStatus.NO_CONTENT_204);
@@ -950,14 +958,9 @@ public class CatalogResourceTest extends BrooklynRestResourceTest {
         assertEquals(applications.get(0).getVersion(), TEST_VERSION);
     }
 
-    @Test
+    @Test(dependsOnMethods = {"testGetOnlyLatestEntity"})
     public void testDeleteOnlyLatestEntity() throws IOException {
-        String symbolicName = "latest.catalog.entity.delete.id";
-        String itemType = "entity";
-        String serviceType = "org.apache.brooklyn.core.test.entity.TestEntity";
-
-        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
-        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+        String symbolicName = "latest.catalog.entity.id";
 
         Response deleteResponse = client().path("/catalog/entities/" + symbolicName + "/latest").delete();
         assertEquals(deleteResponse.getStatus(), HttpStatus.NO_CONTENT_204);
@@ -968,14 +971,9 @@ public class CatalogResourceTest extends BrooklynRestResourceTest {
         assertEquals(applications.get(0).getVersion(), TEST_VERSION);
     }
 
-    @Test
+    @Test(dependsOnMethods = {"testGetOnlyLatestPolicy"})
     public void testDeleteOnlyLatestPolicy() throws IOException {
-        String symbolicName = "latest.catalog.policy.delete.id";
-        String itemType = "policy";
-        String serviceType = "org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy";
-
-        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
-        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+        String symbolicName = "latest.catalog.policy.id";
 
         Response deleteResponse = client().path("/catalog/policies/" + symbolicName + "/latest").delete();
         assertEquals(deleteResponse.getStatus(), HttpStatus.NO_CONTENT_204);
@@ -986,14 +984,9 @@ public class CatalogResourceTest extends BrooklynRestResourceTest {
         assertEquals(applications.get(0).getVersion(), TEST_VERSION);
     }
 
-    @Test
+    @Test(dependsOnMethods = {"testGetOnlyLatestLocation"})
     public void testDeleteOnlyLatestLocation() throws IOException {
-        String symbolicName = "latest.catalog.location.delete.id";
-        String itemType = "location";
-        String serviceType = "localhost";
-
-        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
-        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+        String symbolicName = "latest.catalog.location.id";
 
         Response deleteResponse = client().path("/catalog/locations/" + symbolicName + "/latest").delete();
         assertEquals(deleteResponse.getStatus(), HttpStatus.NO_CONTENT_204);


[4/4] brooklyn-server git commit: This closes #635

Posted by dr...@apache.org.
This closes #635


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

Branch: refs/heads/master
Commit: a069cc5334db0b3792765af6c37d139eaa7b2388
Parents: c80e389 361a0fd
Author: Duncan Godwin <dr...@googlemail.com>
Authored: Fri Apr 14 13:10:32 2017 +0100
Committer: Duncan Godwin <dr...@googlemail.com>
Committed: Fri Apr 14 13:10:32 2017 +0100

----------------------------------------------------------------------
 .../apache/brooklyn/rest/api/CatalogApi.java    |  49 +++++--
 .../rest/resources/CatalogResource.java         |  22 ++++
 .../rest/resources/CatalogResourceTest.java     | 128 ++++++++++++++++++-
 3 files changed, 185 insertions(+), 14 deletions(-)
----------------------------------------------------------------------



[2/4] brooklyn-server git commit: Add unit tests

Posted by dr...@apache.org.
Add unit tests


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

Branch: refs/heads/master
Commit: 6ad3b5c4dd844455de9924ffa85c53df1e3fe295
Parents: 7ba584c
Author: Thomas Bouron <th...@cloudsoftcorp.com>
Authored: Thu Apr 13 18:14:30 2017 +0100
Committer: Thomas Bouron <th...@cloudsoftcorp.com>
Committed: Thu Apr 13 18:14:30 2017 +0100

----------------------------------------------------------------------
 .../rest/resources/CatalogResourceTest.java     | 135 ++++++++++++++++++-
 1 file changed, 130 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6ad3b5c4/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java
index b2b098e..ac2d2d9 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/CatalogResourceTest.java
@@ -22,12 +22,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
-import java.awt.Image;
-import java.awt.Toolkit;
+import java.awt.*;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -69,10 +67,8 @@ import org.apache.brooklyn.util.javalang.Reflections;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.brooklyn.util.stream.Streams;
-import org.apache.http.HttpEntity;
 import org.apache.http.HttpHeaders;
 import org.apache.http.entity.ContentType;
-import org.apache.http.util.EntityUtils;
 import org.eclipse.jetty.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -92,6 +88,7 @@ public class CatalogResourceTest extends BrooklynRestResourceTest {
     private static final Logger log = LoggerFactory.getLogger(CatalogResourceTest.class);
     
     private static String TEST_VERSION = "0.1.2";
+    private static String TEST_LASTEST_VERSION = "0.1.3";
 
     @Override
     protected boolean useLocalScannedCatalog() {
@@ -878,4 +875,132 @@ public class CatalogResourceTest extends BrooklynRestResourceTest {
 
         return f;
     }
+
+    @Test
+    public void testGetOnlyLatestApplication() {
+        String symbolicName = "latest.catalog.application.id";
+        String itemType = "template";
+        String serviceType = "org.apache.brooklyn.core.test.entity.TestEntity";
+
+        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
+        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+
+        CatalogItemSummary application = client().path("/catalog/applications/" + symbolicName + "/latest")
+                .get(CatalogItemSummary.class);
+        assertEquals(application.getVersion(), TEST_LASTEST_VERSION);
+    }
+
+    @Test
+    public void testGetOnlyLatestEntity() {
+        String symbolicName = "latest.catalog.entity.id";
+        String itemType = "entity";
+        String serviceType = "org.apache.brooklyn.core.test.entity.TestEntity";
+
+        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
+        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+
+        CatalogItemSummary application = client().path("/catalog/entities/" + symbolicName + "/latest")
+                .get(CatalogItemSummary.class);
+        assertEquals(application.getVersion(), TEST_LASTEST_VERSION);
+    }
+
+    @Test
+    public void testGetOnlyLatestPolicy() {
+        String symbolicName = "latest.catalog.policy.id";
+        String itemType = "policy";
+        String serviceType = "org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy";
+
+        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
+        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+
+        CatalogItemSummary application = client().path("/catalog/policies/" + symbolicName + "/latest")
+                .get(CatalogItemSummary.class);
+        assertEquals(application.getVersion(), TEST_LASTEST_VERSION);
+    }
+
+    @Test
+    public void testGetOnlyLatestLocation() {
+        String symbolicName = "latest.catalog.location.id";
+        String itemType = "location";
+        String serviceType = "localhost";
+
+        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
+        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+
+        CatalogItemSummary application = client().path("/catalog/policies/" + symbolicName + "/latest")
+                .get(CatalogItemSummary.class);
+        assertEquals(application.getVersion(), TEST_LASTEST_VERSION);
+    }
+
+    @Test
+    public void testDeleteOnlyLatestApplication() throws IOException {
+        String symbolicName = "latest.catalog.application.delete.id";
+        String itemType = "template";
+        String serviceType = "org.apache.brooklyn.core.test.entity.TestEntity";
+
+        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
+        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+
+        Response deleteResponse = client().path("/catalog/applications/" + symbolicName + "/latest").delete();
+        assertEquals(deleteResponse.getStatus(), HttpStatus.NO_CONTENT_204);
+
+        List<CatalogItemSummary> applications = client().path("/catalog/applications").query("fragment", symbolicName)
+                .get(new GenericType<List<CatalogItemSummary>>() {});
+        assertEquals(applications.size(), 1);
+        assertEquals(applications.get(0).getVersion(), TEST_VERSION);
+    }
+
+    @Test
+    public void testDeleteOnlyLatestEntity() throws IOException {
+        String symbolicName = "latest.catalog.entity.delete.id";
+        String itemType = "entity";
+        String serviceType = "org.apache.brooklyn.core.test.entity.TestEntity";
+
+        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
+        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+
+        Response deleteResponse = client().path("/catalog/entities/" + symbolicName + "/latest").delete();
+        assertEquals(deleteResponse.getStatus(), HttpStatus.NO_CONTENT_204);
+
+        List<CatalogItemSummary> applications = client().path("/catalog/entities").query("fragment", symbolicName)
+                .get(new GenericType<List<CatalogItemSummary>>() {});
+        assertEquals(applications.size(), 1);
+        assertEquals(applications.get(0).getVersion(), TEST_VERSION);
+    }
+
+    @Test
+    public void testDeleteOnlyLatestPolicy() throws IOException {
+        String symbolicName = "latest.catalog.policy.delete.id";
+        String itemType = "policy";
+        String serviceType = "org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy";
+
+        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
+        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+
+        Response deleteResponse = client().path("/catalog/policies/" + symbolicName + "/latest").delete();
+        assertEquals(deleteResponse.getStatus(), HttpStatus.NO_CONTENT_204);
+
+        List<CatalogItemSummary> applications = client().path("/catalog/policies").query("fragment", symbolicName)
+                .get(new GenericType<List<CatalogItemSummary>>() {});
+        assertEquals(applications.size(), 1);
+        assertEquals(applications.get(0).getVersion(), TEST_VERSION);
+    }
+
+    @Test
+    public void testDeleteOnlyLatestLocation() throws IOException {
+        String symbolicName = "latest.catalog.location.delete.id";
+        String itemType = "location";
+        String serviceType = "localhost";
+
+        addTestCatalogItem(symbolicName, itemType, TEST_VERSION, serviceType);
+        addTestCatalogItem(symbolicName, itemType, TEST_LASTEST_VERSION, serviceType);
+
+        Response deleteResponse = client().path("/catalog/locations/" + symbolicName + "/latest").delete();
+        assertEquals(deleteResponse.getStatus(), HttpStatus.NO_CONTENT_204);
+
+        List<CatalogItemSummary> applications = client().path("/catalog/locations").query("fragment", symbolicName)
+                .get(new GenericType<List<CatalogItemSummary>>() {});
+        assertEquals(applications.size(), 1);
+        assertEquals(applications.get(0).getVersion(), TEST_VERSION);
+    }
 }