You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2021/05/03 08:29:23 UTC

[brooklyn-server] branch master updated (94a674b -> 0b8bef7)

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

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


    from 94a674b  allow search of some entities even when unmanaged, and better error messages
     new a5362f2  Extend REST API to provide entity relations on GET request
     new 7fadebf  Merge commit '77ae64373497e6bace13b5e1e8786b708694e406' into smart-143
     new e926d63  Test to verify custom relationship via fetch request
     new 0b8bef7  This closes #1168

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/brooklyn/rest/api/EntityApi.java    |   9 ++
 .../brooklyn/rest/domain/RelationSummary.java      |  72 +++++++++
 .../apache/brooklyn/rest/domain/RelationType.java  |  79 ++++++++++
 .../rest/resources/ApplicationResource.java        |   5 +-
 .../brooklyn/rest/resources/EntityResource.java    |  22 +--
 .../brooklyn/rest/util/EntityRelationUtils.java    |  49 +++++++
 .../rest/resources/ApplicationResourceTest.java    |  11 --
 .../resources/EntityRelationsResourceTest.java     | 162 +++++++++++++++++++++
 .../rest/testing/BrooklynRestResourceTest.java     |  11 ++
 9 files changed, 399 insertions(+), 21 deletions(-)
 create mode 100644 rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/RelationSummary.java
 create mode 100644 rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/RelationType.java
 create mode 100644 rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/EntityRelationUtils.java
 create mode 100644 rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityRelationsResourceTest.java

[brooklyn-server] 03/04: Test to verify custom relationship via fetch request

Posted by he...@apache.org.
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

commit e926d639633d50128287eda6b84804919a78d589
Author: Mykola Mandra <my...@cloudsoftcorp.com>
AuthorDate: Mon Apr 26 18:04:51 2021 +0100

    Test to verify custom relationship via fetch request
    
    Signed-off-by: Mykola Mandra <my...@cloudsoftcorp.com>
---
 .../rest/resources/ApplicationResource.java        |  5 +-
 .../brooklyn/rest/resources/EntityResource.java    | 25 ++------
 .../brooklyn/rest/util/EntityRelationUtils.java    | 49 ++++++++++++++++
 .../rest/resources/ApplicationResourceTest.java    | 11 ----
 .../resources/EntityRelationsResourceTest.java     | 66 +++++++++++++++++++---
 .../rest/testing/BrooklynRestResourceTest.java     | 11 ++++
 6 files changed, 127 insertions(+), 40 deletions(-)

diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
index e9803182..fd6887e 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ApplicationResource.java
@@ -80,6 +80,7 @@ import org.apache.brooklyn.rest.transform.ApplicationTransformer;
 import org.apache.brooklyn.rest.transform.EntityTransformer;
 import org.apache.brooklyn.rest.transform.TaskTransformer;
 import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
+import org.apache.brooklyn.rest.util.EntityRelationUtils;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
@@ -185,7 +186,9 @@ public class ApplicationResource extends AbstractBrooklynRestResource implements
         result.setExtraField("creationTimeUtc", entity.getCreationTime());
         addSensorsByGlobs(result, entity, extraSensorGlobs);
         addConfigByGlobs(result, entity, extraConfigGlobs);
-        
+
+        result.setExtraField("relations", EntityRelationUtils.getRelations(entity));
+
         return result;
     }
 
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 8809007..fdd5ea7 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
@@ -24,10 +24,7 @@ import static javax.ws.rs.core.Response.Status.ACCEPTED;
 import static org.apache.brooklyn.rest.util.WebResourceUtils.serviceAbsoluteUriBuilder;
 
 import java.net.URI;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
@@ -40,8 +37,6 @@ import com.google.common.collect.*;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.api.objs.BrooklynObject;
-import org.apache.brooklyn.api.relations.RelationshipType;
 import org.apache.brooklyn.core.mgmt.BrooklynTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTags.NamedStringTag;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
@@ -57,6 +52,7 @@ import org.apache.brooklyn.rest.transform.EntityTransformer;
 import org.apache.brooklyn.rest.transform.LocationTransformer;
 import org.apache.brooklyn.rest.transform.LocationTransformer.LocationDetailLevel;
 import org.apache.brooklyn.rest.transform.TaskTransformer;
+import org.apache.brooklyn.rest.util.EntityRelationUtils;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.ResourceUtils;
@@ -107,24 +103,11 @@ public class EntityResource extends AbstractBrooklynRestResource implements Enti
 
     @Override
     public List<RelationSummary> getRelations(final String applicationId, final String entityId) {
-        List<RelationSummary> entityRelations = Lists.newLinkedList();
-
         Entity entity = brooklyn().getEntity(applicationId, entityId);
         if (entity != null) {
-            for (RelationshipType<?,? extends BrooklynObject> relationship: entity.relations().getRelationshipTypes()) {
-                @SuppressWarnings({ "unchecked", "rawtypes" })
-                Set relations = entity.relations().getRelations((RelationshipType) relationship);
-                Set<String> relationIds = Sets.newLinkedHashSet();
-                for (Object r: relations) {
-                    relationIds.add(((BrooklynObject) r).getId());
-                }
-                RelationType relationType = new RelationType(relationship.getRelationshipTypeName(), relationship.getTargetName(), relationship.getSourceName());
-                RelationSummary relationSummary = new RelationSummary(relationType, relationIds);
-                entityRelations.add(relationSummary);
-            }
+            return EntityRelationUtils.getRelations(entity);
         }
-
-        return entityRelations;
+        return Collections.emptyList();
     }
 
     @Override
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/EntityRelationUtils.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/EntityRelationUtils.java
new file mode 100644
index 0000000..d9c1e7e
--- /dev/null
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/util/EntityRelationUtils.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.util;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.relations.RelationshipType;
+import org.apache.brooklyn.rest.domain.RelationSummary;
+import org.apache.brooklyn.rest.domain.RelationType;
+
+import java.util.List;
+import java.util.Set;
+
+public class EntityRelationUtils {
+
+    public static List<RelationSummary> getRelations(final Entity entity) {
+        List<RelationSummary> entityRelations = Lists.newArrayList();
+        for (RelationshipType<?,? extends BrooklynObject> relationship: entity.relations().getRelationshipTypes()) {
+                @SuppressWarnings({ "unchecked", "rawtypes" })
+                Set relations = entity.relations().getRelations((RelationshipType) relationship);
+                Set<String> relationIds = Sets.newLinkedHashSet();
+                for (Object r: relations) {
+                    relationIds.add(((BrooklynObject) r).getId());
+                }
+                RelationType relationType = new RelationType(relationship.getRelationshipTypeName(), relationship.getTargetName(), relationship.getSourceName());
+                RelationSummary relationSummary = new RelationSummary(relationType, relationIds);
+                entityRelations.add(relationSummary);
+        }
+        return entityRelations;
+    }
+}
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java
index bd85306..311abea 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java
@@ -153,17 +153,6 @@ public class ApplicationResourceTest extends BrooklynRestResourceTest {
         };
     }
 
-    // Convenience for finding a Map within a collection, based on the value of one of its keys
-    private static Predicate<? super Map<?,?>> withValueForKey(final Object key, final Object value) {
-        return new Predicate<Object>() {
-            @Override
-            public boolean apply(Object input) {
-                if (!(input instanceof Map)) return false;
-                return value.equals(((Map<?, ?>) input).get(key));
-            }
-        };
-    }
-
     @Test
     public void testGetUndefinedApplication() {
         try {
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityRelationsResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityRelationsResourceTest.java
index 3d271a4..71e39d7 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityRelationsResourceTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityRelationsResourceTest.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.rest.resources;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.entity.EntityRelations;
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
@@ -28,6 +29,8 @@ import org.apache.brooklyn.rest.domain.RelationSummary;
 import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
 import org.apache.brooklyn.rest.testing.mocks.NameMatcherGroup;
 import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity;
+import org.apache.brooklyn.test.Asserts;
+import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
@@ -36,6 +39,7 @@ import javax.ws.rs.core.Response;
 import java.net.URI;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 import static org.testng.Assert.*;
 
@@ -63,9 +67,9 @@ public class EntityRelationsResourceTest extends BrooklynRestResourceTest {
     }
 
     @Test
-    public void testCustomRelations() {
+    public void testCustomRelationship() {
 
-        // Expect no initial relations.
+        // Expect no initial relationship.
         List<RelationSummary> simpleEntRelations = client().path(
                 URI.create("/applications/simple-app/entities/simple-ent/relations"))
                 .get(new GenericType<List<RelationSummary>>() {});
@@ -75,15 +79,15 @@ public class EntityRelationsResourceTest extends BrooklynRestResourceTest {
         assertTrue(simpleEntRelations.isEmpty());
         assertTrue(simpleGroupRelations.isEmpty());
 
-        // Add custom relation between 'simple-ent' and 'simple-group'.
+        // Add custom relationship between 'simple-ent' and 'simple-group'.
         Collection<Entity> entities = manager.getEntityManager().getEntities();
         Entity simpleEnt = entities.stream().filter(e -> "simple-ent".equals(e.getDisplayName())).findFirst().orElse(null);
         Entity simpleGroup = entities.stream().filter(e -> "simple-group".equals(e.getDisplayName())).findFirst().orElse(null);
-        assertNotNull(simpleEnt, "'simple-ent' was not found");
-        assertNotNull(simpleGroup, "'simple-group' was not found");
+        assertNotNull(simpleEnt, "Did not find 'simple-ent'");
+        assertNotNull(simpleGroup, "Did not find 'simple-group'");
         simpleGroup.relations().add(EntityRelations.HAS_TARGET, simpleEnt);
 
-        // Verify simple-ent relations.
+        // Verify simple-ent relationship.
         simpleEntRelations = client().path(
                 URI.create("/applications/simple-app/entities/simple-ent/relations"))
                 .get(new GenericType<List<RelationSummary>>() {});
@@ -95,7 +99,7 @@ public class EntityRelationsResourceTest extends BrooklynRestResourceTest {
         assertEquals(simpleEntRelationSummary.getTargets().size(), 1, "'simple-ent' must have 1 target only");
         assertTrue(simpleEntRelationSummary.getTargets().contains(simpleGroup.getId()), "'simple-ent' must target id of 'simple-group'");
 
-        // Verify simple-group relations.
+        // Verify simple-group relationship.
         simpleGroupRelations = client().path(
                 URI.create("/applications/simple-app/entities/simple-group/relations"))
                 .get(new GenericType<List<RelationSummary>>() {});
@@ -107,4 +111,52 @@ public class EntityRelationsResourceTest extends BrooklynRestResourceTest {
         assertEquals(simpleGroupRelationSummary.getTargets().size(), 1, "'simple-group' must have 1 target only");
         assertTrue(simpleGroupRelationSummary.getTargets().contains(simpleEnt.getId()), "'simple-group' must target id of 'simple-ent'");
     }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void testCustomRelationshipInFetch() {
+
+        // Add custom relationship between 'simple-ent' and 'simple-group'.
+        Collection<Entity> entities = manager.getEntityManager().getEntities();
+        Entity simpleEnt = entities.stream().filter(e -> "simple-ent".equals(e.getDisplayName())).findFirst().orElse(null);
+        Entity simpleGroup = entities.stream().filter(e -> "simple-group".equals(e.getDisplayName())).findFirst().orElse(null);
+        assertNotNull(simpleEnt, "Did not find 'simple-ent'");
+        assertNotNull(simpleGroup, "Did not find 'simple-group'");
+        simpleGroup.relations().add(EntityRelations.HAS_TARGET, simpleEnt);
+
+        // Get relationship via 'fetch' request.
+        Collection apps = client().path("/applications/fetch").get(Collection.class);
+        Map app = ((Collection<Map>)apps).stream().filter(m -> "simple-app".equals(m.get("name"))).findFirst().orElse(null);
+        Assert.assertNotNull(app, "Did not find 'simple-app'");
+        Collection children = (Collection) app.get("children");
+        Asserts.assertSize(children, 2);
+        Map entitySummary = (Map) Iterables.find(children, withValueForKey("name", "simple-ent"), null);
+        Map groupSummary = (Map) Iterables.find(children, withValueForKey("name", "simple-group"), null);
+        Assert.assertNotNull(entitySummary, "Did not find 'simple-ent'");
+        Assert.assertNotNull(groupSummary,"Did not find 'simple-group'");
+        Collection simpleEntRelations = (Collection) entitySummary.get("relations");
+        Collection simpleGroupRelations = (Collection) groupSummary.get("relations");
+
+        // Verify simple-ent relationship.
+        assertEquals(simpleEntRelations.size(), 1, "'simple-ent' must have 1 relation only");
+        Map simpleEntRelationSummary = (Map) simpleEntRelations.toArray()[0];
+        Map simpleEntRelationSummaryType = (Map) simpleEntRelationSummary.get("type");
+        assertEquals(simpleEntRelationSummaryType.get("name"), "targetted_by");
+        assertEquals(simpleEntRelationSummaryType.get("target"), "targetter");
+        assertEquals(simpleEntRelationSummaryType.get("source"), "target");
+        Collection simpleEntRelationSummaryTargets = (Collection) simpleEntRelationSummary.get("targets");
+        assertEquals(simpleEntRelationSummaryTargets.size(), 1, "'simple-ent' must have 1 target only");
+        assertTrue(simpleEntRelationSummaryTargets.contains(simpleGroup.getId()), "'simple-ent' must target id of 'simple-group'");
+
+        // Verify simple-group relationship.
+        assertEquals(simpleGroupRelations.size(), 1, "'simple-group' must have 1 relation only");
+        Map simpleGroupRelationSummary = (Map) simpleGroupRelations.toArray()[0];
+        Map simpleGroupRelationSummaryType = (Map) simpleGroupRelationSummary.get("type");
+        assertEquals(simpleGroupRelationSummaryType.get("name"), "has_target");
+        assertEquals(simpleGroupRelationSummaryType.get("target"), "target");
+        assertEquals(simpleGroupRelationSummaryType.get("source"), "targetter");
+        Collection simpleGroupRelationSummaryTargets = (Collection) simpleEntRelationSummary.get("targets");
+        assertEquals(simpleGroupRelationSummaryTargets.size(), 1, "'simple-ent' must have 1 target only");
+        assertTrue(simpleGroupRelationSummaryTargets.contains(simpleGroup.getId()), "'simple-ent' must target id of 'simple-group'");
+    }
 }
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java
index a1c1067..576a535 100644
--- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/testing/BrooklynRestResourceTest.java
@@ -34,6 +34,7 @@ import javax.ws.rs.client.Entity;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import com.google.common.base.Predicate;
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
@@ -234,4 +235,14 @@ public abstract class BrooklynRestResourceTest extends BrooklynRestApiTest {
         return WebClient.create(getEndpointAddress(), clientProviders);
     }
 
+    // Convenience for finding a Map within a collection, based on the value of one of its keys
+    protected static Predicate<? super Map<?,?>> withValueForKey(final Object key, final Object value) {
+        return new Predicate<Object>() {
+            @Override
+            public boolean apply(Object input) {
+                if (!(input instanceof Map)) return false;
+                return value.equals(((Map<?, ?>) input).get(key));
+            }
+        };
+    }
 }

[brooklyn-server] 02/04: Merge commit '77ae64373497e6bace13b5e1e8786b708694e406' into smart-143

Posted by he...@apache.org.
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

commit 7fadebf5c1dbb00f20731abf550a5af0898ba71a
Merge: a5362f2 77ae643
Author: Mykola Mandra <my...@cloudsoftcorp.com>
AuthorDate: Wed Apr 21 17:22:59 2021 +0100

    Merge commit '77ae64373497e6bace13b5e1e8786b708694e406' into smart-143

 .../main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java    | 3 ++-
 .../config/external/PropertiesFileExternalConfigSupplierTest.java    | 5 -----
 karaf/features/src/main/feature/feature.xml                          | 1 +
 pom.xml                                                              | 1 +
 4 files changed, 4 insertions(+), 6 deletions(-)

[brooklyn-server] 01/04: Extend REST API to provide entity relations on GET request

Posted by he...@apache.org.
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

commit a5362f23d6d4cbb3b47bd1e611d32e92641e32be
Author: Mykola Mandra <my...@cloudsoftcorp.com>
AuthorDate: Wed Apr 21 16:49:00 2021 +0100

    Extend REST API to provide entity relations on GET request
    
    Signed-off-by: Mykola Mandra <my...@cloudsoftcorp.com>
---
 .../org/apache/brooklyn/rest/api/EntityApi.java    |   9 ++
 .../brooklyn/rest/domain/RelationSummary.java      |  72 ++++++++++++++
 .../apache/brooklyn/rest/domain/RelationType.java  |  79 +++++++++++++++
 .../brooklyn/rest/resources/EntityResource.java    |  33 +++++--
 .../resources/EntityRelationsResourceTest.java     | 110 +++++++++++++++++++++
 5 files changed, 297 insertions(+), 6 deletions(-)

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 9455575..5bbd5b3 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
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.rest.api;
 
 import io.swagger.annotations.Api;
+import org.apache.brooklyn.rest.domain.RelationSummary;
 import org.apache.brooklyn.rest.domain.EntitySummary;
 import org.apache.brooklyn.rest.domain.LocationSummary;
 import org.apache.brooklyn.rest.domain.TaskSummary;
@@ -74,6 +75,14 @@ public interface EntityApi {
             @PathParam("application") final String application,
             @PathParam("entity") final String entity);
 
+    @GET
+    @ApiOperation(value = "Fetch the list of relations of an entity",
+            response = RelationSummary.class)
+    @Path("/{entity}/relations")
+    List<RelationSummary> getRelations(
+            @PathParam("application") final String applicationId,
+            @PathParam("entity") final String entityId);
+
     @POST
     @ApiOperation(value = "Add a child or children to this entity given a YAML spec",
             response = org.apache.brooklyn.rest.domain.TaskSummary.class)
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/RelationSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/RelationSummary.java
new file mode 100644
index 0000000..255f49f
--- /dev/null
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/RelationSummary.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.domain;
+
+import com.fasterxml.jackson.annotation.*;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.Set;
+
+public class RelationSummary implements Serializable {
+
+    private static final long serialVersionUID = -3273187304766851859L;
+
+    private final RelationType type;
+    private final Set<String> targets;
+
+    public RelationSummary(
+            @JsonProperty("type") RelationType type,
+            @JsonProperty("targets") Set<String> targets) {
+        this.type = type;
+        this.targets = (targets == null) ? ImmutableSet.of() : ImmutableSet.copyOf(targets);
+    }
+
+    public RelationType getType() {
+        return type;
+    }
+
+    public Set<String> getTargets() {
+        return targets;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof RelationSummary)) return false;
+        RelationSummary that = (RelationSummary) o;
+        return Objects.equals(type, that.type)
+                && Objects.equals(targets, that.targets);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type, targets);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("type", type)
+                .add("targets", targets)
+                .toString();
+    }
+}
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/RelationType.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/RelationType.java
new file mode 100644
index 0000000..c740ce3
--- /dev/null
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/RelationType.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.Set;
+
+public class RelationType implements Serializable {
+
+    private static final long serialVersionUID = -6467217117683357832L;
+
+    private final String name;
+    private final String target;
+    private final String source;
+
+    public RelationType(
+            @JsonProperty("name") String name,
+            @JsonProperty("target") String target,
+            @JsonProperty("source") String source) {
+        this.name = name;
+        this.target = target;
+        this.source = source;
+    }
+
+    public String getName() {
+        return name;
+    }
+    public String getTarget() {
+        return target;
+    }
+    public String getSource() {
+        return source;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof RelationType)) return false;
+        RelationType that = (RelationType) o;
+        return Objects.equals(name, that.name)
+                && Objects.equals(target, that.target)
+                && Objects.equals(source, that.source);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, target, source);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("name", name)
+                .add("target", target)
+                .add("source", source)
+                .toString();
+    }
+}
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 f66d821..8809007 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
@@ -27,6 +27,7 @@ import java.net.URI;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
@@ -35,9 +36,12 @@ import javax.ws.rs.core.Response.ResponseBuilder;
 import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 
+import com.google.common.collect.*;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.relations.RelationshipType;
 import org.apache.brooklyn.core.mgmt.BrooklynTags;
 import org.apache.brooklyn.core.mgmt.BrooklynTags.NamedStringTag;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
@@ -47,9 +51,7 @@ import org.apache.brooklyn.core.mgmt.entitlement.EntitlementPredicates;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 import org.apache.brooklyn.core.typereg.RegisteredTypes;
 import org.apache.brooklyn.rest.api.EntityApi;
-import org.apache.brooklyn.rest.domain.EntitySummary;
-import org.apache.brooklyn.rest.domain.LocationSummary;
-import org.apache.brooklyn.rest.domain.TaskSummary;
+import org.apache.brooklyn.rest.domain.*;
 import org.apache.brooklyn.rest.filter.HaHotStateRequired;
 import org.apache.brooklyn.rest.transform.EntityTransformer;
 import org.apache.brooklyn.rest.transform.LocationTransformer;
@@ -64,9 +66,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Objects;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
 import com.google.common.io.Files;
 
 @HaHotStateRequired
@@ -107,6 +106,28 @@ public class EntityResource extends AbstractBrooklynRestResource implements Enti
     }
 
     @Override
+    public List<RelationSummary> getRelations(final String applicationId, final String entityId) {
+        List<RelationSummary> entityRelations = Lists.newLinkedList();
+
+        Entity entity = brooklyn().getEntity(applicationId, entityId);
+        if (entity != null) {
+            for (RelationshipType<?,? extends BrooklynObject> relationship: entity.relations().getRelationshipTypes()) {
+                @SuppressWarnings({ "unchecked", "rawtypes" })
+                Set relations = entity.relations().getRelations((RelationshipType) relationship);
+                Set<String> relationIds = Sets.newLinkedHashSet();
+                for (Object r: relations) {
+                    relationIds.add(((BrooklynObject) r).getId());
+                }
+                RelationType relationType = new RelationType(relationship.getRelationshipTypeName(), relationship.getTargetName(), relationship.getSourceName());
+                RelationSummary relationSummary = new RelationSummary(relationType, relationIds);
+                entityRelations.add(relationSummary);
+            }
+        }
+
+        return entityRelations;
+    }
+
+    @Override
     public Response addChildren(String applicationToken, String entityToken, Boolean start, String timeoutS, String yaml) {
         final Entity parent = brooklyn().getEntity(applicationToken, entityToken);
         if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_ENTITY, parent)) {
diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityRelationsResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityRelationsResourceTest.java
new file mode 100644
index 0000000..3d271a4
--- /dev/null
+++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/EntityRelationsResourceTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.rest.resources;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.entity.EntityRelations;
+import org.apache.brooklyn.rest.domain.ApplicationSpec;
+import org.apache.brooklyn.rest.domain.EntitySpec;
+import org.apache.brooklyn.rest.domain.RelationSummary;
+import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
+import org.apache.brooklyn.rest.testing.mocks.NameMatcherGroup;
+import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.Response;
+import java.net.URI;
+import java.util.Collection;
+import java.util.List;
+
+import static org.testng.Assert.*;
+
+@Test(singleThreaded = true,
+        // by using a different suite name we disallow interleaving other tests between the methods of this test class, which wrecks the test fixtures
+        suiteName = "EntityRelationsResourceTest")
+public class EntityRelationsResourceTest extends BrooklynRestResourceTest {
+
+    @BeforeClass(alwaysRun = true)
+    private void setUp() throws Exception {
+        // Deploy an application that we'll use to read the relations of.
+        startServer();
+        final ApplicationSpec applicationSpec = ApplicationSpec.builder().name("simple-app")
+                .entities(ImmutableSet.of(
+                        new EntitySpec("simple-ent", RestMockSimpleEntity.class.getName()),
+                        new EntitySpec("simple-group", NameMatcherGroup.class.getName(), ImmutableMap.of("namematchergroup.regex", "simple-ent"))
+                ))
+                .locations(ImmutableSet.of("localhost"))
+                .build();
+        Response response = clientDeploy(applicationSpec);
+        int status = response.getStatus();
+        assertTrue(status >= 200 && status <= 299, "expected HTTP Response of 2xx but got " + status);
+        URI applicationUri = response.getLocation();
+        waitForApplicationToBeRunning(applicationUri);
+    }
+
+    @Test
+    public void testCustomRelations() {
+
+        // Expect no initial relations.
+        List<RelationSummary> simpleEntRelations = client().path(
+                URI.create("/applications/simple-app/entities/simple-ent/relations"))
+                .get(new GenericType<List<RelationSummary>>() {});
+        List<RelationSummary> simpleGroupRelations = client().path(
+                URI.create("/applications/simple-app/entities/simple-group/relations"))
+                .get(new GenericType<List<RelationSummary>>() {});
+        assertTrue(simpleEntRelations.isEmpty());
+        assertTrue(simpleGroupRelations.isEmpty());
+
+        // Add custom relation between 'simple-ent' and 'simple-group'.
+        Collection<Entity> entities = manager.getEntityManager().getEntities();
+        Entity simpleEnt = entities.stream().filter(e -> "simple-ent".equals(e.getDisplayName())).findFirst().orElse(null);
+        Entity simpleGroup = entities.stream().filter(e -> "simple-group".equals(e.getDisplayName())).findFirst().orElse(null);
+        assertNotNull(simpleEnt, "'simple-ent' was not found");
+        assertNotNull(simpleGroup, "'simple-group' was not found");
+        simpleGroup.relations().add(EntityRelations.HAS_TARGET, simpleEnt);
+
+        // Verify simple-ent relations.
+        simpleEntRelations = client().path(
+                URI.create("/applications/simple-app/entities/simple-ent/relations"))
+                .get(new GenericType<List<RelationSummary>>() {});
+        assertEquals(simpleEntRelations.size(), 1, "'simple-ent' must have 1 relation only");
+        RelationSummary simpleEntRelationSummary = simpleEntRelations.get(0);
+        assertEquals(simpleEntRelationSummary.getType().getName(), "targetted_by");
+        assertEquals(simpleEntRelationSummary.getType().getTarget(), "targetter");
+        assertEquals(simpleEntRelationSummary.getType().getSource(), "target");
+        assertEquals(simpleEntRelationSummary.getTargets().size(), 1, "'simple-ent' must have 1 target only");
+        assertTrue(simpleEntRelationSummary.getTargets().contains(simpleGroup.getId()), "'simple-ent' must target id of 'simple-group'");
+
+        // Verify simple-group relations.
+        simpleGroupRelations = client().path(
+                URI.create("/applications/simple-app/entities/simple-group/relations"))
+                .get(new GenericType<List<RelationSummary>>() {});
+        assertEquals(simpleGroupRelations.size(), 1, "'simple-group' must have 1 relation only");
+        RelationSummary simpleGroupRelationSummary = simpleGroupRelations.get(0);
+        assertEquals(simpleGroupRelationSummary.getType().getName(), "has_target");
+        assertEquals(simpleGroupRelationSummary.getType().getTarget(), "target");
+        assertEquals(simpleGroupRelationSummary.getType().getSource(), "targetter");
+        assertEquals(simpleGroupRelationSummary.getTargets().size(), 1, "'simple-group' must have 1 target only");
+        assertTrue(simpleGroupRelationSummary.getTargets().contains(simpleEnt.getId()), "'simple-group' must target id of 'simple-ent'");
+    }
+}

[brooklyn-server] 04/04: This closes #1168

Posted by he...@apache.org.
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

commit 0b8bef713a0aeaada88ba33eefc043ad8866dabf
Merge: 94a674b e926d63
Author: Alex Heneveld <al...@cloudsoftcorp.com>
AuthorDate: Mon May 3 09:29:14 2021 +0100

    This closes #1168

 .../org/apache/brooklyn/rest/api/EntityApi.java    |   9 ++
 .../brooklyn/rest/domain/RelationSummary.java      |  72 +++++++++
 .../apache/brooklyn/rest/domain/RelationType.java  |  79 ++++++++++
 .../rest/resources/ApplicationResource.java        |   5 +-
 .../brooklyn/rest/resources/EntityResource.java    |  22 +--
 .../brooklyn/rest/util/EntityRelationUtils.java    |  49 +++++++
 .../rest/resources/ApplicationResourceTest.java    |  11 --
 .../resources/EntityRelationsResourceTest.java     | 162 +++++++++++++++++++++
 .../rest/testing/BrooklynRestResourceTest.java     |  11 ++
 9 files changed, 399 insertions(+), 21 deletions(-)