brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [1/3] git commit: entity tags support, including REST API (but not GUI)
Date Fri, 27 Jun 2014 11:42:45 GMT
Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 3780a9c71 -> 69c58f306


entity tags support, including REST API (but not GUI)


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

Branch: refs/heads/master
Commit: 1601276c5da1361ef174eed81cb4e68ca12f48d7
Parents: 3780a9c
Author: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Authored: Fri Jun 27 10:32:33 2014 +0100
Committer: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Committed: Fri Jun 27 12:02:49 2014 +0100

----------------------------------------------------------------------
 api/src/main/java/brooklyn/entity/Entity.java   |  18 +++
 .../java/brooklyn/mementos/EntityMemento.java   |   4 +-
 .../brooklyn/entity/basic/AbstractEntity.java   |  30 +++++
 .../entity/rebind/BasicEntityRebindSupport.java |   7 ++
 .../entity/rebind/dto/BasicEntityMemento.java   |   9 ++
 .../entity/rebind/dto/MementosGenerators.java   |   4 +
 .../brooklyn/entity/basic/EntitiesTest.java     |  21 ++++
 .../entity/rebind/RebindEntityTest.java         |  17 +++
 .../main/java/brooklyn/rest/api/EntityApi.java  |  12 +-
 .../brooklyn/rest/resources/EntityResource.java |   7 ++
 .../brooklyn/rest/resources/PolicyResource.java |  24 ++--
 .../brooklyn/rest/resources/SensorResource.java |   2 +
 .../rest/transform/EntityTransformer.java       |   1 +
 .../rest/resources/ApiDocResourceTest.java      |   2 +-
 .../rest/resources/EntityResourceTest.java      | 123 +++++++++++++++++++
 .../rest/resources/SensorResourceTest.java      |  23 +---
 16 files changed, 270 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/api/src/main/java/brooklyn/entity/Entity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/entity/Entity.java b/api/src/main/java/brooklyn/entity/Entity.java
index 3e1a77f..2f66832 100644
--- a/api/src/main/java/brooklyn/entity/Entity.java
+++ b/api/src/main/java/brooklyn/entity/Entity.java
@@ -2,9 +2,13 @@ package brooklyn.entity;
 
 import java.util.Collection;
 import java.util.Map;
+import java.util.Set;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.collect.ImmutableMap;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.entity.proxying.EntitySpec;
@@ -209,4 +213,18 @@ public interface Entity extends Identifiable {
      * @return True if the policy enricher at this entity; false otherwise
      */
     boolean removeEnricher(Enricher enricher);
+    
+    /** 
+     * Tags are arbitrary objects which can be attached to an entity for subsequent reference.
+     * They must not be null (as {@link ImmutableMap} may be used under the covers; also
there is little point!);
+     * and they should be amenable to our persistence (on-disk serialization) and our JSON
serialization in the REST API.
+     * 
+     * @return An immutable copy of the set of tags on this entity. 
+     * Note {@link #containsTag(Object)} will be more efficient,
+     * and {@link #addTag(Object)} and {@link #removeTag(Object)} will not work. */
+    Set<Object> getTags();
+    boolean addTag(@Nonnull Object tag);
+    boolean removeTag(@Nonnull Object tag);
+    boolean containsTag(@Nonnull Object tag);
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/api/src/main/java/brooklyn/mementos/EntityMemento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/mementos/EntityMemento.java b/api/src/main/java/brooklyn/mementos/EntityMemento.java
index 966bedd..b971dd0 100644
--- a/api/src/main/java/brooklyn/mementos/EntityMemento.java
+++ b/api/src/main/java/brooklyn/mementos/EntityMemento.java
@@ -54,5 +54,7 @@ public interface EntityMemento extends Memento, TreeNode {
      * The ids of the enrichers of this entity.
      */
     public Collection<String> getEnrichers();
-    
+
+    public Collection<Object> getTags();
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index bf05f86..4c4d688 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -70,6 +70,7 @@ import com.google.common.base.Objects;
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -156,6 +157,7 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal
{
     Map<String,Object> presentationAttributes = Maps.newLinkedHashMap();
     Collection<AbstractPolicy> policies = Lists.newCopyOnWriteArrayList();
     Collection<AbstractEnricher> enrichers = Lists.newCopyOnWriteArrayList();
+    Set<Object> tags = Sets.newLinkedHashSet();
 
     // FIXME we do not currently support changing parents, but to implement a cluster that
can shrink we need to support at least
     // orphaning (i.e. removing ownership). This flag notes if the entity has previously
had a parent, and if an attempt is made to
@@ -1261,6 +1263,34 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal
{
     }
 
     @Override
+    public Set<Object> getTags() {
+        synchronized (tags) {
+            return ImmutableSet.copyOf(tags);
+        }
+    }
+
+    @Override
+    public boolean addTag(Object tag) {
+        synchronized (tags) {
+            return tags.add(tag);
+        }
+    }    
+
+    @Override
+    public boolean removeTag(Object tag) {
+        synchronized (tags) {
+            return tags.remove(tag);
+        }
+    }    
+
+    @Override
+    public boolean containsTag(Object tag) {
+        synchronized (tags) {
+            return tags.contains(tag);
+        }
+    }    
+    
+    @Override
     protected void finalize() throws Throwable {
         super.finalize();
         if (!getManagementSupport().wasDeployed())

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
index 0bb51f3..9ab4a8b 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
@@ -91,6 +91,7 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento>
{
         addPolicies(rebindContext, memento);
         addEnrichers(rebindContext, memento);
         addMembers(rebindContext, memento);
+        addTags(rebindContext, memento);
         addLocations(rebindContext, memento);
 
         doReconstruct(rebindContext, memento);
@@ -122,6 +123,12 @@ public class BasicEntityRebindSupport implements RebindSupport<EntityMemento>
{
         }
     }
     
+    protected void addTags(RebindContext rebindContext, EntityMemento memento) {
+        for (Object tag : memento.getTags()) {
+            entity.addTag(tag);
+        }
+    }
+    
     protected void addChildren(RebindContext rebindContext, EntityMemento memento) {
         for (String childId : memento.getChildren()) {
             Entity child = rebindContext.getEntity(childId);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java b/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
index 9ded4f7..81ab906 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/BasicEntityMemento.java
@@ -52,6 +52,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements
Entit
         protected List<String> enrichers = Lists.newArrayList();
         protected List<String> members = Lists.newArrayList();
         protected List<Effector<?>> effectors = Lists.newArrayList();
+        protected List<Object> tags = Lists.newArrayList();
         
         public Builder from(EntityMemento other) {
             super.from((TreeNode)other);
@@ -65,6 +66,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements
Entit
             enrichers.addAll(other.getEnrichers());
             members.addAll(other.getMembers());
             effectors.addAll(other.getEffectors());
+            tags.addAll(other.getTags());
             return this;
         }
         public EntityMemento build() {
@@ -84,6 +86,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements
Entit
     private Map<String, Object> attributes;
     private List<String> policies;
     private List<String> enrichers;
+    private List<Object> tags;
     
     // TODO can we move some of these to entity type, or remove/re-insert those which are
final statics?
     private Map<String, ConfigKey<?>> configKeys;
@@ -112,6 +115,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements
Entit
         policies = toPersistedList(builder.policies);
         enrichers = toPersistedList(builder.enrichers);
         members = toPersistedList(builder.members);
+        tags = toPersistedList(builder.tags);
         
         effectors = toPersistedList(builder.effectors);
         
@@ -256,6 +260,10 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements
Entit
         return fromPersistedList(members);
     }
     
+    public List<Object> getTags() {
+        return fromPersistedList(tags);
+    }
+    
     @Override
     public List<String> getLocations() {
         return fromPersistedList(locations);
@@ -270,6 +278,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements
Entit
                 .add("attributes", Entities.sanitize(getAttributes()))
                 .add("policies", getPolicies())
                 .add("enrichers", getEnrichers())
+                .add("tags", getTags())
                 .add("locations", getLocations());
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
index 4f8d0fe..6b7eda9 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
@@ -139,6 +139,10 @@ public class MementosGenerators {
             builder.enrichers.add(enricher.getId()); 
         }
         
+        for (Object tag : entity.getTags()) {
+            builder.tags.add(tag); 
+        }
+        
         Entity parentEntity = entity.getParent();
         builder.parent = (parentEntity != null) ? parentEntity.getId() : null;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java b/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
index 00413ab..1b08185 100644
--- a/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EntitiesTest.java
@@ -18,6 +18,7 @@ import brooklyn.location.basic.SimulatedLocation;
 import brooklyn.test.Asserts;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.test.entity.TestEntity;
+import brooklyn.util.collections.MutableSet;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
@@ -91,4 +92,24 @@ public class EntitiesTest {
         // And now that it's set, the attribute-when-ready should return immediately
         assertEquals(Entities.attributeSupplierWhenReady(entity, TestEntity.NAME).get(),
"myname");
     }
+    
+    @Test
+    public void testCreateGetContainsAndRemoveTags() throws Exception {
+        entity.addTag("foo");
+        entity.addTag(app);
+        
+        Assert.assertTrue(entity.containsTag("foo"));
+        Assert.assertFalse(entity.containsTag("bar"));
+        
+        Assert.assertEquals(entity.getTags(), MutableSet.of(app, "foo"));
+        
+        entity.removeTag("foo");
+        Assert.assertFalse(entity.containsTag("foo"));
+        
+        Assert.assertTrue(entity.containsTag(entity.getParent()));
+        Assert.assertFalse(entity.containsTag(entity));
+        
+        Assert.assertEquals(entity.getTags(), MutableSet.of(app));
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
index 5405f1c..290cc3b 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
@@ -51,6 +51,7 @@ import brooklyn.test.entity.TestApplication;
 import brooklyn.test.entity.TestEntity;
 import brooklyn.test.entity.TestEntityImpl;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Durations;
@@ -249,6 +250,22 @@ public class RebindEntityTest extends RebindTestFixtureWithApp {
         assertEquals(newReffer.resizable, newE);
     }
     
+    @Test
+    public void testEntityTags() throws Exception {
+        MyEntity origE = origApp.createAndManageChild(EntitySpec.create(MyEntity.class));
+        origE.addTag("foo");
+        origE.addTag(origApp);
+
+        newApp = rebind(false);
+        MyEntity newE = Iterables.getOnlyElement( Entities.descendants(newApp, MyEntity.class)
);
+
+        assertTrue(newE.containsTag("foo"), "tags are "+newE.getTags());
+        assertFalse(newE.containsTag("bar"));
+        assertTrue(newE.containsTag(newE.getParent()));
+        assertTrue(newE.containsTag(origApp));
+        assertEquals(newE.getTags(), MutableSet.of("foo", newE.getParent()));
+    }
+
     public static class ReffingEntity {
         public Group group;
         public Resizable resizable;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/usage/rest-api/src/main/java/brooklyn/rest/api/EntityApi.java
----------------------------------------------------------------------
diff --git a/usage/rest-api/src/main/java/brooklyn/rest/api/EntityApi.java b/usage/rest-api/src/main/java/brooklyn/rest/api/EntityApi.java
index f51d6c7..abd3d94 100644
--- a/usage/rest-api/src/main/java/brooklyn/rest/api/EntityApi.java
+++ b/usage/rest-api/src/main/java/brooklyn/rest/api/EntityApi.java
@@ -88,7 +88,17 @@ public interface EntityApi {
           @PathParam("application") final String application,
           @PathParam("entity") final String entity
   );
-  
+
+  @GET
+  @Path("/{entity}/tags")
+  @ApiOperation(value = "Fetch list of tags on this entity")
+  @ApiErrors(value = {
+      @ApiError(code = 404, reason = "Could not find application or entity")
+  })
+  public List<Object> listTags(
+          @ApiParam(value = "Entity ID or name", required = true) @PathParam("application")
String applicationId,
+          @ApiParam(value = "Application ID or name", required = true) @PathParam("entity")
String entityId);
+
   @POST
   @ApiOperation(
       value = "Expunge an entity",

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
index 142bab4..0efeb56 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityResource.java
@@ -35,6 +35,7 @@ import brooklyn.rest.transform.LocationTransformer.LocationDetailLevel;
 import brooklyn.rest.transform.TaskTransformer;
 import brooklyn.rest.util.WebResourceUtils;
 import brooklyn.util.ResourceUtils;
+import brooklyn.util.collections.MutableList;
 
 public class EntityResource extends AbstractBrooklynRestResource implements EntityApi {
 
@@ -83,6 +84,12 @@ public class EntityResource extends AbstractBrooklynRestResource implements
Enti
   }
 
   @Override
+  public List<Object> listTags(String applicationId, String entityId) {
+      Entity entity = brooklyn().getEntity(applicationId, entityId);
+      return MutableList.copyOf(entity.getTags());
+  }
+
+  @Override
   public Response getIcon(String applicationId, String entityId) {
       EntityLocal entity = brooklyn().getEntity(applicationId, entityId);
       String url = entity.getIconUrl();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/usage/rest-server/src/main/java/brooklyn/rest/resources/PolicyResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/PolicyResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/PolicyResource.java
index 9c8b4a2..423fdc0 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/PolicyResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/PolicyResource.java
@@ -1,28 +1,28 @@
 package brooklyn.rest.resources;
 
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.policy.Policy;
 import brooklyn.policy.basic.Policies;
 import brooklyn.rest.api.PolicyApi;
-import brooklyn.rest.transform.ApplicationTransformer;
-import brooklyn.rest.transform.PolicyTransformer;
 import brooklyn.rest.domain.PolicySummary;
 import brooklyn.rest.domain.Status;
+import brooklyn.rest.transform.ApplicationTransformer;
+import brooklyn.rest.transform.PolicyTransformer;
 import brooklyn.util.exceptions.Exceptions;
+
 import com.google.common.base.Function;
 import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.ws.rs.core.Response;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.collect.Iterables.transform;
 
 public class PolicyResource extends AbstractBrooklynRestResource implements PolicyApi {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
index 2ce7580..eea2a8c 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
@@ -43,6 +43,7 @@ public class SensorResource extends AbstractBrooklynRestResource implements
Sens
 
     private static final Logger log = LoggerFactory.getLogger(SensorResource.class);
 
+    @SuppressWarnings("rawtypes")
     @Override
     public List<SensorSummary> list(final String application, final String entityToken)
{
         final EntityLocal entity = brooklyn().getEntity(application, entityToken);
@@ -60,6 +61,7 @@ public class SensorResource extends AbstractBrooklynRestResource implements
Sens
     public Map<String, Object> batchSensorRead(final String application, final String
entityToken, final Boolean raw) {
         final EntityLocal entity = brooklyn().getEntity(application, entityToken);
         Map<String, Object> sensorMap = Maps.newHashMap();
+        @SuppressWarnings("rawtypes")
         Iterable<AttributeSensor> sensors = filter(entity.getEntityType().getSensors(),
AttributeSensor.class);
 
         for (AttributeSensor<?> sensor : sensors) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/usage/rest-server/src/main/java/brooklyn/rest/transform/EntityTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/EntityTransformer.java
b/usage/rest-server/src/main/java/brooklyn/rest/transform/EntityTransformer.java
index 2722935..a8a7431 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/transform/EntityTransformer.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/EntityTransformer.java
@@ -47,6 +47,7 @@ public class EntityTransformer {
                 .put("policies", URI.create(entityUri + "/policies"))
                 .put("activities", URI.create(entityUri + "/activities"))
                 .put("locations", URI.create(entityUri + "/locations"))
+                .put("tags", URI.create(entityUri + "/tags"))
                 .put("catalog", URI.create("/v1/catalog/entities/" + type))
                 .put("expunge", URI.create(entityUri + "/expunge")
             );

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/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 e6332e8..0141814 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
@@ -54,7 +54,7 @@ public class ApiDocResourceTest extends BrooklynRestResourceTest {
     @Test
     public void testEntityDetails() throws Exception {
         Documentation response = client().resource("/v1/apidoc/brooklyn.rest.resources.EntityResource").get(Documentation.class);
-        assertEquals(countOperations(response), 10);
+        assertEquals(countOperations(response), 11);
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java
b/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java
new file mode 100644
index 0000000..ae1a2f4
--- /dev/null
+++ b/usage/rest-server/src/test/java/brooklyn/rest/resources/EntityResourceTest.java
@@ -0,0 +1,123 @@
+package brooklyn.rest.resources;
+
+import java.util.List;
+
+import javax.annotation.Nullable;
+import javax.ws.rs.core.MediaType;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.config.render.RendererHints;
+import brooklyn.config.render.TestRendererHints;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.event.AttributeSensor;
+import brooklyn.rest.api.SensorApi;
+import brooklyn.rest.domain.ApplicationSpec;
+import brooklyn.rest.domain.EntitySpec;
+import brooklyn.rest.testing.BrooklynRestResourceTest;
+import brooklyn.rest.testing.mocks.RestMockSimpleEntity;
+import brooklyn.util.collections.MutableList;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.GenericType;
+
+/**
+ * Test the {@link SensorApi} implementation.
+ * <p>
+ * Check that {@link SensorResource} correctly renders {@link AttributeSensor}
+ * values, including {@link RendererHints.DisplayValue} hints.
+ */
+@Test(singleThreaded = true)
+public class EntityResourceTest extends BrooklynRestResourceTest {
+
+    private final ApplicationSpec simpleSpec = ApplicationSpec.builder()
+            .name("simple-app")
+            .entities(ImmutableSet.of(new EntitySpec("simple-ent", RestMockSimpleEntity.class.getName())))
+            .locations(ImmutableSet.of("localhost"))
+            .build();
+
+    private EntityInternal entity;
+
+    private static final String entityEndpoint = "/v1/applications/simple-app/entities/simple-ent";
+
+    /**
+     * Sets up the application and entity.
+     * <p>
+     * Adds a sensor and sets its value to {@code 12345}. Configures a display value
+     * hint that appends {@code frogs} to the value of the sensor.
+     */
+    @BeforeClass(alwaysRun = true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        // Deploy application
+        ClientResponse deploy = clientDeploy(simpleSpec);
+        waitForApplicationToBeRunning(deploy.getLocation());
+
+        // Add tag
+        entity = (EntityInternal) Iterables.find(getManagementContext().getEntityManager().getEntities(),
new Predicate<Entity>() {
+            @Override
+            public boolean apply(@Nullable Entity input) {
+                return "RestMockSimpleEntity".equals(input.getEntityType().getSimpleName());
+            }
+        });
+    }
+
+    @AfterClass(alwaysRun = true)
+    @Override
+    public void tearDown() throws Exception {
+        TestRendererHints.clearRegistry();
+        super.tearDown();
+    }
+
+    @Test
+    public void testTagsSanity() throws Exception {
+        entity.addTag("foo");
+        
+        ClientResponse response = client().resource(entityEndpoint + "/tags")
+                .accept(MediaType.APPLICATION_JSON)
+                .get(ClientResponse.class);
+        List<Object> tags = response.getEntity(new GenericType<List<Object>>(List.class)
{});
+
+        Assert.assertTrue(tags.contains("foo"));
+        Assert.assertFalse(tags.contains("bar"));
+    }
+    
+    // TODO any entity or complex object should be cleaned up as part of WebResourceUtils
call
+    @Test(groups="WIP")
+    public void testTagsDoNotSerializeTooMuch() throws Exception {
+        entity.addTag("foo");
+        entity.addTag(entity.getParent());
+
+        ClientResponse response = client().resource(entityEndpoint + "/tags")
+                .accept(MediaType.APPLICATION_JSON)
+                .get(ClientResponse.class);
+        List<Object> tags = response.getEntity(new GenericType<List<Object>>(List.class)
{});
+
+        Assert.assertEquals(tags.size(), 2, "tags are: "+tags);
+        
+        Assert.assertTrue(tags.contains("foo"));
+        Assert.assertFalse(tags.contains("bar"));
+        
+        MutableList<Object> appTags = MutableList.copyOf(tags);
+        appTags.remove("foo");
+        Object appTag = Iterables.getOnlyElement( appTags );
+        Assert.assertTrue((""+appTag).contains(entity.getParent().getId()), "unexpected app
tag, does not include ID: "+appTag);
+        
+        Assert.assertTrue((""+appTag).length() < 1000, "unexpected app tag, includes too
much mgmt info (len "+(""+appTag).length()+"): "+appTag);
+        
+        Assert.assertFalse((""+appTag).contains(entity.getManagementContext().getManagementNodeId()),
"unexpected app tag, includes too much mgmt info: "+appTag);
+        Assert.assertFalse((""+appTag).contains("managementContext"), "unexpected app tag,
includes too much mgmt info: "+appTag);
+        Assert.assertFalse((""+appTag).contains("localhost"), "unexpected app tag, includes
too much mgmt info: "+appTag);
+        Assert.assertFalse((""+appTag).contains("catalog"), "unexpected app tag, includes
too much mgmt info: "+appTag);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1601276c/usage/rest-server/src/test/java/brooklyn/rest/resources/SensorResourceTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/brooklyn/rest/resources/SensorResourceTest.java
b/usage/rest-server/src/test/java/brooklyn/rest/resources/SensorResourceTest.java
index 3d71c3c..c57bf69 100644
--- a/usage/rest-server/src/test/java/brooklyn/rest/resources/SensorResourceTest.java
+++ b/usage/rest-server/src/test/java/brooklyn/rest/resources/SensorResourceTest.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2014 by Cloudsoft Corporation Limited
- *
- * Licensed 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.resources;
 
 import static org.testng.Assert.assertEquals;
@@ -39,12 +24,12 @@ import brooklyn.rest.testing.BrooklynRestResourceTest;
 import brooklyn.rest.testing.mocks.RestMockSimpleEntity;
 import brooklyn.util.text.StringFunctions;
 
-import com.sun.jersey.api.client.ClientResponse;
-
 import com.google.common.base.Functions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.GenericType;
 
 /**
  * Test the {@link SensorApi} implementation.
@@ -107,7 +92,7 @@ public class SensorResourceTest extends BrooklynRestResourceTest {
         ClientResponse response = client().resource(sensorsEndpoint + "/current-state")
                 .accept(MediaType.APPLICATION_JSON)
                 .get(ClientResponse.class);
-        Map<String, ?> currentState = response.getEntity(Map.class);
+        Map<String, ?> currentState = response.getEntity(new GenericType<Map<String,?>>(Map.class)
{});
 
         for (String sensor : currentState.keySet()) {
             if (sensor.equals(sensorName)) {
@@ -123,7 +108,7 @@ public class SensorResourceTest extends BrooklynRestResourceTest {
                 .queryParam("raw", "true")
                 .accept(MediaType.APPLICATION_JSON)
                 .get(ClientResponse.class);
-        Map<String, ?> currentState = response.getEntity(Map.class);
+        Map<String, ?> currentState = response.getEntity(new GenericType<Map<String,?>>(Map.class)
{});
 
         for (String sensor : currentState.keySet()) {
             if (sensor.equals(sensorName)) {


Mime
View raw message