This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git


The following commit(s) were added to refs/heads/master by this push:
     new 603680b  add rest api methods for modifying entity tags
603680b is described below

commit 603680bc44294ac85562cbd23f1e1a77c92d2393
Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com>
AuthorDate: Tue Oct 26 15:59:19 2021 +0100

    add rest api methods for modifying entity tags
---
 .../apache/brooklyn/core/mgmt/BrooklynTags.java    | 12 +++++
 .../org/apache/brooklyn/rest/api/EntityApi.java    | 57 ++++++++++++++++++++++
 .../brooklyn/rest/resources/EntityResource.java    | 25 ++++++++++
 .../rest/resources/EntityResourceTest.java         | 43 +++++++++++++++-
 4 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTags.java 
b/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTags.java
index a9188c1..7c13fd0 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTags.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/BrooklynTags.java
@@ -25,6 +25,7 @@ import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+import org.apache.brooklyn.api.objs.BrooklynObject.TagSupport;
 import org.apache.brooklyn.core.resolve.jackson.BeanWithTypeUtils;
 import org.apache.brooklyn.util.collections.MutableList;
 
@@ -104,6 +105,17 @@ public class BrooklynTags {
         }
     }
 
+    public static <T> void upsertSingleKeyMapValueTag(TagSupport tagS, String 
key, T value) {
+        MutableList<Object> matchingKeyTags = MutableList.of();
+        tagS.getTags().stream().forEach(t -> {
+            if (isTagSingleKeyMap(t, key)) {
+                matchingKeyTags.add(t);
+            }
+        });
+        matchingKeyTags.forEach(tagS::removeTag);
+        tagS.addTag(MutableMap.of(key, value));
+    }
+
     public static NamedStringTag findFirstNamedStringTag(String kind, 
Iterable<Object> tags) {
         return findFirstOfKind(kind, NamedStringTag.class, tags);
     }
diff --git 
a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityApi.java 
b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityApi.java
index 6c35f69..b5dc946 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/EntityApi.java
@@ -167,6 +167,63 @@ public interface EntityApi {
             @ApiParam(value = "Application ID or name", required = true) 
@PathParam("application") String applicationId,
             @ApiParam(value = "Entity ID or name", required = true) 
@PathParam("entity") String entityId);
 
+    // this feels too dangerous; see other items
+//    @POST
+//    @Path("/{entity}/tags")
+//    @ApiOperation(value = "Set the tags on this entity (replaces all, use 
with care)")
+//    @ApiResponses(value = {
+//            @ApiResponse(code = 404, message = "Could not find application 
or entity")
+//    })
+//    public void setTags(
+//            @ApiParam(value = "Application ID or name", required = true) 
@PathParam("application") String applicationId,
+//            @ApiParam(value = "Entity ID or name", required = true) 
@PathParam("entity") String entityId,
+//            @ApiParam(value = "Tags to set", required = true) List<Object> 
tags);
+
+    @POST
+    @Path("/{entity}/tag/add")
+    @ApiOperation(value = "Add a tag on this entity")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application or 
entity")
+    })
+    public void addTag(
+            @ApiParam(value = "Application ID or name", required = true) 
@PathParam("application") String applicationId,
+            @ApiParam(value = "Entity ID or name", required = true) 
@PathParam("entity") String entityId,
+            @ApiParam(value = "Tag to add", required = true) Object tag);
+
+    @POST
+    @Path("/{entity}/tag/delete")
+    @ApiOperation(value = "Delete a tag on this entity, returning whether the 
tag was found (and deleted)")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application or 
entity")
+    })
+    public boolean deleteTag(
+            @ApiParam(value = "Application ID or name", required = true) 
@PathParam("application") String applicationId,
+            @ApiParam(value = "Entity ID or name", required = true) 
@PathParam("entity") String entityId,
+            @ApiParam(value = "Tag to delete", required = true) Object tag);
+
+    @POST
+    @Path("/{entity}/tag/upsert/{tagKey}")
+    @ApiOperation(value = "Inserts a tag which is a single-key map with the 
given key (path parameter) and value (post body), removing any existing tag 
matching the key")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application or 
entity")
+    })
+    public void upsertTag(
+            @ApiParam(value = "Application ID or name", required = true) 
@PathParam("application") String applicationId,
+            @ApiParam(value = "Entity ID or name", required = true) 
@PathParam("entity") String entityId,
+            @ApiParam(value = "Entity ID or name", required = true) 
@PathParam("tagKey") String tagKey,
+            @ApiParam(value = "Tag map value to upsert for the given key", 
required = true) Object tagValue);
+
+    @GET
+    @Path("/{entity}/tag/get/{tagKey}")
+    @ApiOperation(value = "Returns the tag value for a tag which is a 
single-key map with the given key, or null (not 404 for missing tag key)")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Could not find application or 
entity")
+    })
+    public Object getTag(
+            @ApiParam(value = "Application ID or name", required = true) 
@PathParam("application") String applicationId,
+            @ApiParam(value = "Entity ID or name", required = true) 
@PathParam("entity") String entityId,
+            @ApiParam(value = "Entity ID or name", required = true) 
@PathParam("tagKey") String tagKey);
+
     @POST
     @ApiOperation(
             value = "Rename an entity"
diff --git 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java
 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java
index a068402..dc17a21 100644
--- 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java
+++ 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.rest.resources;
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.status;
 import static javax.ws.rs.core.Response.Status.ACCEPTED;
+import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTags.SpecSummary;
 import static 
org.apache.brooklyn.rest.util.WebResourceUtils.serviceAbsoluteUriBuilder;
 
@@ -257,6 +258,30 @@ public class EntityResource extends 
AbstractBrooklynRestResource implements Enti
     }
 
     @Override
+    public void addTag(String applicationId, String entityId, Object tag) {
+        Entity entity = brooklyn().getEntity(applicationId, entityId);
+        entity.tags().addTag(tag);
+    }
+
+    @Override
+    public boolean deleteTag(String applicationId, String entityId, Object 
tag) {
+        Entity entity = brooklyn().getEntity(applicationId, entityId);
+        return entity.tags().removeTag(tag);
+    }
+
+    @Override
+    public void upsertTag(String applicationId, String entityId, String 
tagKey, Object tagValue) {
+        Entity entity = brooklyn().getEntity(applicationId, entityId);
+        BrooklynTags.upsertSingleKeyMapValueTag(entity.tags(), tagKey, 
tagValue);
+    }
+
+    @Override
+    public Object getTag(String applicationId, String entityId, String tagKey) 
{
+        Entity entity = brooklyn().getEntity(applicationId, entityId);
+        return BrooklynTags.findSingleKeyMapValue(tagKey, Object.class, 
entity.tags().getTags());
+    }
+
+    @Override
     public Response getIcon(String applicationId, String entityId) {
         Entity entity = brooklyn().getEntity(applicationId, entityId);
         String url = RegisteredTypes.getIconUrl(entity);
diff --git 
a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityResourceTest.java
 
b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityResourceTest.java
index 59af350..00e41d3 100644
--- 
a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityResourceTest.java
+++ 
b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityResourceTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.brooklyn.rest.resources;
 
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableMap;
 import static org.testng.Assert.assertEquals;
 
 import java.util.Collection;
@@ -227,5 +229,44 @@ public class EntityResourceTest extends 
BrooklynRestResourceTest {
         Assert.assertEquals( ((Entity)appTag).getId(), 
entity.getApplicationId(), "Wrong ID: "+appTag);
         Assert.assertTrue(appTag instanceof BasicApplication, "Should have 
deserialized BasicApplication: "+appTag);
     }
-    
+
+    @Test
+    public void testTagsChangingViaRest() throws Exception {
+        entity.tags().addTag("foo");
+
+        Response response;
+
+        response = client().path(entityEndpoint + 
"/tag/add").accept(MediaType.APPLICATION_JSON).post(toJsonEntity("bar"));
+        HttpAsserts.assertHealthyStatusCode(response.getStatus());
+
+        response = client().path(entityEndpoint + 
"/tag/add").accept(MediaType.APPLICATION_JSON).post(toJsonEntity(MutableMap.of("baz_key",
 "baz_value")));
+        HttpAsserts.assertHealthyStatusCode(response.getStatus());
+
+        String raw;
+        response = client().path(entityEndpoint + 
"/tags").accept(MediaType.APPLICATION_JSON).get();
+        raw = response.readEntity(String.class);
+        log.info("TAGS raw: "+raw);
+        HttpAsserts.assertHealthyStatusCode(response.getStatus());
+        Asserts.assertStringContains(raw, "foo");
+        Asserts.assertStringContains(raw, "bar");
+        Asserts.assertStringContains(raw, "baz_key", "baz_value");
+
+        response = client().path(entityEndpoint + 
"/tag/upsert/baz_key").accept(MediaType.APPLICATION_JSON).post(toJsonEntity("baz2_value"));
+        HttpAsserts.assertHealthyStatusCode(response.getStatus());
+        response = client().path(entityEndpoint + 
"/tags").accept(MediaType.APPLICATION_JSON).get();
+        raw = response.readEntity(String.class);
+        Asserts.assertStringContains(raw, "baz_key", "baz2_value");
+        Asserts.assertStringDoesNotContain(raw, "baz_value");
+
+        response = client().path(entityEndpoint + 
"/tag/delete").accept(MediaType.APPLICATION_JSON).post(toJsonEntity("bar"));
+        HttpAsserts.assertHealthyStatusCode(response.getStatus());
+        response = client().path(entityEndpoint + 
"/tag/delete").accept(MediaType.APPLICATION_JSON).post(toJsonEntity(MutableMap.of("baz_key",
 "baz2_value")));
+        HttpAsserts.assertHealthyStatusCode(response.getStatus());
+        response = client().path(entityEndpoint + 
"/tags").accept(MediaType.APPLICATION_JSON).get();
+        raw = response.readEntity(String.class);
+        Asserts.assertStringDoesNotContain(raw, "bar");
+        Asserts.assertStringDoesNotContain(raw, "baz_key");
+        Asserts.assertStringContains(raw, "foo");
+    }
+
 }

Reply via email to