brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [10/17] git commit: expand the vocabulary for looking for entities in a given scope, simplify access to scope (use `descendant("xyz")`) and simplify access to config/attrWhenReady on the same node, and use static inner classes in YAML DSL objects
Date Mon, 01 Sep 2014 16:14:48 GMT
expand the vocabulary for looking for entities in a given scope, simplify access to scope (use
`descendant("xyz")`) and  simplify access to config/attrWhenReady on the same node, and use
static inner classes in YAML DSL objects


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

Branch: refs/heads/master
Commit: c6d6cc4aa3800ac361b55956abe10f9dc8dfe7dc
Parents: 05a3948
Author: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Authored: Mon Sep 1 11:00:39 2014 +0100
Committer: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Committed: Mon Sep 1 17:07:00 2014 +0100

----------------------------------------------------------------------
 .../java/brooklyn/entity/basic/Entities.java    |  28 ++++
 .../spi/dsl/methods/BrooklynDslCommon.java      | 106 ++++++++----
 .../brooklyn/spi/dsl/methods/DslComponent.java  | 165 +++++++++++++------
 .../camp/brooklyn/EntitiesYamlTest.java         |  65 +++++++-
 .../brooklyn/ReferencingYamlTestEntity.java     |   8 +
 .../resources/test-referencing-entities.yaml    |  23 ++-
 .../util/collections/CollectionFunctionals.java |  23 +++
 .../java/brooklyn/util/guava/Functionals.java   |  12 ++
 8 files changed, 333 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/core/src/main/java/brooklyn/entity/basic/Entities.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/Entities.java b/core/src/main/java/brooklyn/entity/basic/Entities.java
index 4191110..77f2f5f 100644
--- a/core/src/main/java/brooklyn/entity/basic/Entities.java
+++ b/core/src/main/java/brooklyn/entity/basic/Entities.java
@@ -26,6 +26,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -579,6 +580,33 @@ public class Entities {
     }
     
     /**
+     * returns the entity, its parent, its parent, and so on. */ 
+    public static Iterable<Entity> ancestors(final Entity root) {
+        return new Iterable<Entity>() {
+            @Override
+            public Iterator<Entity> iterator() {
+                return new Iterator<Entity>() {
+                    Entity next = root;
+                    @Override
+                    public boolean hasNext() {
+                        return next!=null;
+                    }
+                    @Override
+                    public Entity next() {
+                        Entity result = next;
+                        next = next.getParent();
+                        return result;
+                    }
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
      * Registers a {@link BrooklynShutdownHooks#invokeStopOnShutdown(Entity)} to shutdown
this entity when the JVM exits.
      * (Convenience method located in this class for easy access.)
      */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
index 16c3b35..0fdea54 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
@@ -21,6 +21,7 @@ package io.brooklyn.camp.brooklyn.spi.dsl.methods;
 import io.brooklyn.camp.brooklyn.spi.creation.EntitySpecConfiguration;
 import io.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier;
 import io.brooklyn.camp.brooklyn.spi.dsl.DslUtils;
+import io.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope;
 
 import java.util.Map;
 
@@ -34,49 +35,47 @@ import brooklyn.util.exceptions.Exceptions;
 /** static import functions which can be used in `$brooklyn:xxx` contexts */
 public class BrooklynDslCommon {
 
-    public static Object literal(Object expression) {
-        return expression;
+    // --- access specific entities
+    
+    public static DslComponent entity(String scopeOrId) {
+        return new DslComponent(Scope.GLOBAL, scopeOrId);
+    }
+    public static DslComponent parent() {
+        return new DslComponent(Scope.PARENT, null);
+    }
+    public static DslComponent child(String scopeOrId) {
+        return new DslComponent(Scope.CHILD, scopeOrId);
+    }
+    public static DslComponent sibling(String scopeOrId) {
+        return new DslComponent(Scope.SIBLING, scopeOrId);
+    }
+    public static DslComponent descendant(String scopeOrId) {
+        return new DslComponent(Scope.DESCENDANT, scopeOrId);
+    }
+    public static DslComponent ancestor(String scopeOrId) {
+        return new DslComponent(Scope.ANCESTOR, scopeOrId);
+    }
+    // prefer the syntax above to the below now -- but not deprecating the below
+    public static DslComponent component(String scopeOrId) {
+        return component("global", scopeOrId);
     }
-
-	public static DslComponent component(String id) {
-		return component("global", id);
-	}
-	
 	public static DslComponent component(String scope, String id) {
 	    if (!DslComponent.Scope.isValid(scope)) {
-	        throw new IllegalArgumentException(scope + " is not a vlaid scope");
+	        throw new IllegalArgumentException(scope + " is not a valid scope");
 	    }
 	    return new DslComponent(DslComponent.Scope.fromString(scope), id);
 	}
-	
-	/** returns a DslParsedObject<String> OR a String if it is fully resolved */
-    public static Object formatString(final String pattern, final Object ...args) {
-        if (DslUtils.resolved(args)) {
-            // if all args are resolved, apply the format string now
-            return String.format(pattern, args);
-        }
-        return new FormatString(pattern, args);
-    }
 
-    protected static final class FormatString extends BrooklynDslDeferredSupplier<String>
{
-        private static final long serialVersionUID = -4849297712650560863L;
-        private String pattern;
-        private Object[] args;
+    // --- access things on entities
 
-        public FormatString(String pattern, Object ...args) {
-            this.pattern = pattern;
-            this.args = args;
-        }
-        @Override
-        public Task<String> newTask() {
-            return DependentConfiguration.formatString(pattern, args);
-        }
-        @Override
-        public String toString() {
-            return "$brooklyn:formatString("+pattern+")";
-        }
+    public static BrooklynDslDeferredSupplier<?> config(String keyName) {
+        return new DslComponent(Scope.THIS, "").config(keyName); 
     }
-    
+
+    public static BrooklynDslDeferredSupplier<?> attributeWhenReady(String sensorName)
{
+        return new DslComponent(Scope.THIS, "").attributeWhenReady(sensorName); 
+    }
+
     // TODO: Would be nice to have sensor(String sensorName), which would take the sensor
from the entity in question, 
     //       but that would require refactoring of Brooklyn DSL
     // TODO: Should use catalog's classloader, rather than Class.forName; how to get that?
Should we return a future?!
@@ -100,10 +99,47 @@ public class BrooklynDslCommon {
         } catch (ClassNotFoundException e) {
             throw Exceptions.propagate(e);
         }
-        
     }
 
+    // --- build complex things
+    
     public static EntitySpecConfiguration entitySpec(Map<String, Object> arguments)
{
         return new EntitySpecConfiguration(arguments);
     }
+    
+    // --- string manipulation
+
+    /** return a literal string -- ie skip parsing */
+    public static Object literal(Object expression) {
+        return expression;
+    }
+
+    /** returns a DslParsedObject<String> OR a String if it is fully resolved */
+    public static Object formatString(final String pattern, final Object ...args) {
+        if (DslUtils.resolved(args)) {
+            // if all args are resolved, apply the format string now
+            return String.format(pattern, args);
+        }
+        return new FormatString(pattern, args);
+    }
+
+    protected static final class FormatString extends BrooklynDslDeferredSupplier<String>
{
+        private static final long serialVersionUID = -4849297712650560863L;
+        private String pattern;
+        private Object[] args;
+
+        public FormatString(String pattern, Object ...args) {
+            this.pattern = pattern;
+            this.args = args;
+        }
+        @Override
+        public Task<String> newTask() {
+            return DependentConfiguration.formatString(pattern, args);
+        }
+        @Override
+        public String toString() {
+            return "$brooklyn:formatString("+pattern+")";
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
index a1c96c4..e339f1e 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
@@ -27,6 +27,8 @@ import java.util.concurrent.Callable;
 
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
@@ -34,6 +36,7 @@ import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.event.basic.Sensors;
 import brooklyn.management.Task;
 import brooklyn.management.internal.EntityManagerInternal;
+import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.TaskBuilder;
 import brooklyn.util.task.Tasks;
 
@@ -41,13 +44,13 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
 
 public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 
     private static final long serialVersionUID = -7715984495268724954L;
     
     private final String componentId;
+	private final DslComponent scopeComponent;
 	private final Scope scope;
 
 	public DslComponent(String componentId) {
@@ -55,47 +58,66 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity>
{
 	}
 	
 	public DslComponent(Scope scope, String componentId) {
+	    this(null, scope, componentId);
+	}
+	
+	public DslComponent(DslComponent scopeComponent, Scope scope, String componentId) {
 	    Preconditions.checkNotNull(scope, "scope");
+	    this.scopeComponent = scopeComponent;
 	    this.componentId = componentId;
 	    this.scope = scope;
 	}
 
+	// ---------------------------
+	
     @Override
     public Task<Entity> newTask() {
         return TaskBuilder.<Entity>builder().name("component("+componentId+")").body(
-            new EntityInScopeFinder(scope, componentId)).build();
+            new EntityInScopeFinder(scopeComponent, scope, componentId)).build();
     }
     
     protected static class EntityInScopeFinder implements Callable<Entity> {
-        protected Scope scope;
-        protected String componentId;
+        protected final DslComponent scopeComponent;
+        protected final Scope scope;
+        protected final String componentId;
 
-        public EntityInScopeFinder(Scope scope, String componentId) {
+        public EntityInScopeFinder(DslComponent scopeComponent, Scope scope, String componentId)
{
+            this.scopeComponent = scopeComponent;
             this.scope = scope;
             this.componentId = componentId;
         }
 
+        protected EntityInternal getEntity() {
+            if (scopeComponent!=null) {
+                return (EntityInternal)scopeComponent.get();
+            } else {
+                return entity();
+            }
+        }
+        
         @Override
         public Entity call() throws Exception {
             Iterable<Entity> entitiesToSearch = null;
             switch (scope) {
                 case THIS:
-                    return entity();
+                    return getEntity();
                 case PARENT:
-                    return entity().getParent();
+                    return getEntity().getParent();
                 case GLOBAL:
-                    entitiesToSearch = ((EntityManagerInternal)entity().getManagementContext().getEntityManager())
+                    entitiesToSearch = ((EntityManagerInternal)getEntity().getManagementContext().getEntityManager())
                         .getAllEntitiesInApplication( entity().getApplication() );
                     break;
                 case DESCENDANT:
-                    entitiesToSearch = Sets.newLinkedHashSet();
-                    addDescendants(entity(), (Set<Entity>)entitiesToSearch);
+                    entitiesToSearch = Entities.descendants(getEntity());
+                    break;
+                case ANCESTOR:
+                    entitiesToSearch = Entities.ancestors(getEntity());
                     break;
                 case SIBLING:
-                    entitiesToSearch = entity().getParent().getChildren();
+                    entitiesToSearch = getEntity().getParent().getChildren();
                     break;
                 case CHILD:
-                    entitiesToSearch = entity().getChildren();
+                    entitiesToSearch = getEntity().getChildren();
                     break;
                 default:
                     throw new IllegalStateException("Unexpected scope "+scope);
@@ -107,31 +129,66 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity>
{
                 return result.get();
             
             // TODO may want to block and repeat on new entities joining?
-            throw new NoSuchElementException("No entity matching id " + componentId);
+            throw new NoSuchElementException("No entity matching id " + componentId+
+                (scope==Scope.GLOBAL ? "" : ", in scope "+scope+" wrt "+getEntity()+
+                (scopeComponent!=null ? " ("+scopeComponent+" from "+entity()+")" : "")));
         }        
     }
     
-    private static void addDescendants(Entity entity, Set<Entity> entities) {
-        entities.add(entity);
-        for (Entity child : entity.getChildren()) {
-            addDescendants(child, entities);
+    // -------------------------------
+
+    // DSL words which move to a new component
+    
+    public DslComponent entity(String scopeOrId) {
+        return new DslComponent(this, Scope.GLOBAL, scopeOrId);
+    }
+    public DslComponent child(String scopeOrId) {
+        return new DslComponent(this, Scope.CHILD, scopeOrId);
+    }
+    public DslComponent sibling(String scopeOrId) {
+        return new DslComponent(this, Scope.SIBLING, scopeOrId);
+    }
+    public DslComponent descendant(String scopeOrId) {
+        return new DslComponent(this, Scope.DESCENDANT, scopeOrId);
+    }
+    public DslComponent ancestor(String scopeOrId) {
+        return new DslComponent(this, Scope.ANCESTOR, scopeOrId);
+    }
+    
+    @Deprecated /** @deprecated since 0.7.0 */
+    public DslComponent component(String scopeOrId) {
+        return new DslComponent(this, Scope.GLOBAL, scopeOrId);
+    }
+    
+    public DslComponent parent() {
+        return new DslComponent(this, Scope.PARENT, "");
+    }
+    
+    public DslComponent component(String scope, String id) {
+        if (!DslComponent.Scope.isValid(scope)) {
+            throw new IllegalArgumentException(scope + " is not a vlaid scope");
         }
+        return new DslComponent(this, DslComponent.Scope.fromString(scope), id);
     }
+
+    // DSL words which return things
     
 	public BrooklynDslDeferredSupplier<?> attributeWhenReady(final String sensorName)
{
-		return new AttributeWhenReady(sensorName);
+		return new AttributeWhenReady(this, sensorName);
 	}
 	// class simply makes the memento XML files nicer
-	protected class AttributeWhenReady extends BrooklynDslDeferredSupplier<Object> {
+	protected static class AttributeWhenReady extends BrooklynDslDeferredSupplier<Object>
{
         private static final long serialVersionUID = 1740899524088902383L;
-        private String sensorName;
-        public AttributeWhenReady(String sensorName) {
+        private final DslComponent component;
+        private final String sensorName;
+        public AttributeWhenReady(DslComponent component, String sensorName) {
+            this.component = Preconditions.checkNotNull(component);
             this.sensorName = sensorName;
         }
         @SuppressWarnings("unchecked")
         @Override
         public Task<Object> newTask() {
-            Entity targetEntity = DslComponent.this.get();
+            Entity targetEntity = component.get();
             Sensor<?> targetSensor = targetEntity.getEntityType().getSensor(sensorName);
             if (!(targetSensor instanceof AttributeSensor<?>)) {
                 targetSensor = Sensors.newSensor(Object.class, sensorName);
@@ -140,39 +197,50 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity>
{
         }
         @Override
         public String toString() {
-            return DslComponent.this.toString()+"."+"attributeWhenReady("+sensorName+")";
+            return component.toString()+"."+"attributeWhenReady("+sensorName+")";
         }
 	}
-	
-	public BrooklynDslDeferredSupplier<Object> config(final String keyName) {
-        return new BrooklynDslDeferredSupplier<Object>() {
-            private static final long serialVersionUID = -4735177561947722511L;
-            @Override
-            public Task<Object> newTask() {
-                return Tasks.builder().name("retrieving config for "+keyName).dynamic(false).body(new
Callable<Object>() {
-                    @Override
-                    public Object call() throws Exception {
-                        Entity targetEntity = DslComponent.this.get();
-                        return targetEntity.getConfig(ConfigKeys.newConfigKey(Object.class,
keyName));
-                    }
-                }).build();
-            }
-            @Override
-            public String toString() {
-                return DslComponent.this.toString()+"."+"config("+keyName+")";
-            }
-        };
+
+	public BrooklynDslDeferredSupplier<?> config(final String keyName) {
+        return new DslConfigSupplier(this, keyName);
     }
-	
+    protected final static class DslConfigSupplier extends BrooklynDslDeferredSupplier<Object>
{
+        private final DslComponent component;
+        private final String keyName;
+        private static final long serialVersionUID = -4735177561947722511L;
+
+        public DslConfigSupplier(DslComponent component, String keyName) {
+            this.component = Preconditions.checkNotNull(component);
+            this.keyName = keyName;
+        }
+
+        @Override
+        public Task<Object> newTask() {
+            return Tasks.builder().name("retrieving config for "+keyName).dynamic(false).body(new
Callable<Object>() {
+                @Override
+                public Object call() throws Exception {
+                    Entity targetEntity = component.get();
+                    return targetEntity.getConfig(ConfigKeys.newConfigKey(Object.class, keyName));
+                }
+            }).build();
+        }
+
+        @Override
+        public String toString() {
+            return component.toString()+"."+"config("+keyName+")";
+        }
+    }
+
 	public static enum Scope {
 	    GLOBAL ("global"),
 	    CHILD ("child"),
 	    PARENT ("parent"),
 	    SIBLING ("sibling"),
 	    DESCENDANT ("descendant"),
+	    ANCESTOR("ancestor"),
 	    THIS ("this");
 	    
-	    public static final Set<Scope> VALUES = ImmutableSet.of(GLOBAL, CHILD, PARENT,
SIBLING, DESCENDANT, THIS);
+	    public static final Set<Scope> VALUES = ImmutableSet.of(GLOBAL, CHILD, PARENT,
SIBLING, DESCENDANT, ANCESTOR, THIS);
 	    
 	    private final String name;
 	    
@@ -181,10 +249,14 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity>
{
 	    }
 	    
 	    public static Scope fromString(String name) {
+	        return tryFromString(name).get();
+	    }
+	    
+	    public static Maybe<Scope> tryFromString(String name) {
 	        for (Scope scope : VALUES)
 	            if (scope.name.toLowerCase().equals(name.toLowerCase()))
-	                return scope;
-	        throw new IllegalArgumentException(name + " is not a valid scope");
+	                return Maybe.of(scope);
+	        return Maybe.absent(new IllegalArgumentException(name + " is not a valid scope"));
 	    }
 	    
 	    public static boolean isValid(String name) {
@@ -199,6 +271,7 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity>
{
     @Override
     public String toString() {
         return "$brooklyn:component("+
+            (scopeComponent==null ? "" : scopeComponent+", ")+
             (scope==Scope.GLOBAL ? "" : scope+", ")+
             componentId+
             ")";

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index 53bb4aa..588faf0 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -21,6 +21,9 @@ package io.brooklyn.camp.brooklyn;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
+import io.brooklyn.camp.brooklyn.spi.dsl.methods.BrooklynDslCommon;
+import io.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent;
+import io.brooklyn.camp.brooklyn.spi.dsl.methods.DslComponent.Scope;
 
 import java.io.StringReader;
 import java.util.Iterator;
@@ -43,7 +46,9 @@ import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.BasicEntity;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityFunctions;
 import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.SameServerEntity;
 import brooklyn.entity.effector.Effectors;
@@ -56,8 +61,13 @@ import brooklyn.management.Task;
 import brooklyn.management.internal.EntityManagerInternal;
 import brooklyn.test.entity.TestEntity;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Functionals;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
+import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -350,9 +360,33 @@ public class EntitiesYamlTest extends AbstractYamlTest {
     }
 
     @Test
+    public void testMultipleReferencesJava() throws Exception {
+        final Entity app = createAndStartApplication(loadYaml("test-referencing-entities.yaml"));
+        waitForApplicationTasks(app);
+        
+        Entity c1 = Tasks.resolving(new DslComponent("c1").newTask(), Entity.class).context(
((EntityInternal)app).getExecutionContext() ).embedResolutionInTask(true).get();
+        Assert.assertEquals(c1, Entities.descendants(app, EntityPredicates.displayNameEqualTo("child
1")).iterator().next());
+        
+        Entity e1 = Tasks.resolving(new DslComponent(Scope.PARENT, "xxx").newTask(), Entity.class).context(
((EntityInternal)c1).getExecutionContext() ).embedResolutionInTask(true).get();
+        Assert.assertEquals(e1, Entities.descendants(app, EntityPredicates.displayNameEqualTo("entity
1")).iterator().next());
+        
+        Entity c1a = Tasks.resolving(BrooklynDslCommon.descendant("c1").newTask(), Entity.class).context(
((EntityInternal)e1).getExecutionContext() ).embedResolutionInTask(true).get();
+        Assert.assertEquals(c1a, c1);
+        Entity e1a = Tasks.resolving(BrooklynDslCommon.ancestor("e1").newTask(), Entity.class).context(
((EntityInternal)c1).getExecutionContext() ).embedResolutionInTask(true).get();
+        Assert.assertEquals(e1a, e1);
+        try {
+            Tasks.resolving(BrooklynDslCommon.ancestor("c1").newTask(), Entity.class).context(
((EntityInternal)e1).getExecutionContext() ).embedResolutionInTask(true).get();
+            Assert.fail("Should not have found c1 as ancestor of e1");
+        } catch (Exception e) { /* expected */ }
+    }
+    
+    @Test
     public void testMultipleReferences() throws Exception {
         final Entity app = createAndStartApplication(loadYaml("test-referencing-entities.yaml"));
         waitForApplicationTasks(app);
+        
+        Entities.dumpInfo(app);
+        
         Assert.assertEquals(app.getDisplayName(), "test-referencing-entities");
 
         Entity entity1 = null, entity2 = null, child1 = null, child2 = null, grandchild1
= null, grandchild2 = null;
@@ -390,6 +424,7 @@ public class EntitiesYamlTest extends AbstractYamlTest {
         Map<ConfigKey<Entity>, Entity> keyToEntity = new ImmutableMap.Builder<ConfigKey<Entity>,
Entity>()
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_APP, app)
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_ENTITY1, entity1)
+            .put(ReferencingYamlTestEntity.TEST_REFERENCE_ENTITY1_ALT, entity1)
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_ENTITY2, entity2)
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_CHILD1, child1)
             .put(ReferencingYamlTestEntity.TEST_REFERENCE_CHILD2, child2)
@@ -404,22 +439,36 @@ public class EntitiesYamlTest extends AbstractYamlTest {
             }
         }).get();
 
-        for (Entity entityInApp : entitiesInApp)
+        for (Entity entityInApp : entitiesInApp) {
             checkReferences(entityInApp, keyToEntity);
+            try {
+                getResolvedConfigInTask(entityInApp, ReferencingYamlTestEntity.TEST_REFERENCE_BOGUS);
+                Assert.fail("Should not have resolved "+ReferencingYamlTestEntity.TEST_REFERENCE_BOGUS+"
at "+entityInApp);
+            } catch (Exception e) {
+                /* expected */
+            }
+        }
     }
 
     private void checkReferences(final Entity entity, Map<ConfigKey<Entity>, Entity>
keyToEntity) throws Exception {
         for (final ConfigKey<Entity> key : keyToEntity.keySet()) {
-            Entity fromConfig = ((EntityInternal)entity).getExecutionContext().submit(MutableMap.of(),
new Callable<Entity>() {
-                @Override
-                public Entity call() throws Exception {
-                    return (Entity) entity.getConfig(key);
-                }
-            }).get();
-            Assert.assertEquals(fromConfig, keyToEntity.get(key));
+            try {
+                Assert.assertEquals(getResolvedConfigInTask(entity, key).get(), keyToEntity.get(key));
+            } catch (Throwable t) {
+                Exceptions.propagateIfFatal(t);
+                Assert.fail("Wrong value for "+entity+":"+key+", "+entity.getConfigRaw(key,
 false)+": "+t, t);
+            }
         }
     }
 
+    private Maybe<Entity> getResolvedConfigInTask(final Entity entity, final ConfigKey<Entity>
key) {
+        return Tasks.resolving(Tasks.<Entity>builder().body(
+            Functionals.callable(Suppliers.compose(EntityFunctions.config(key), Suppliers.ofInstance(entity)))
).build())
+            .as(Entity.class)
+            .context( ((EntityInternal)entity).getExecutionContext() ).embedResolutionInTask(true)
+            .getMaybe();
+    }
+
     public void testWithAppLocation() throws Exception {
         Entity app = createAndStartApplication(loadYaml("test-entity-basic-template.yaml",
 
             "location: localhost:(name=yaml name)"));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
index ca6c5a3..02d778a 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencingYamlTestEntity.java
@@ -36,6 +36,10 @@ public interface ReferencingYamlTestEntity extends Entity {
             .name("test.reference.entity1")
             .build();    
     @SuppressWarnings("serial")
+    public static final ConfigKey<Entity> TEST_REFERENCE_ENTITY1_ALT = BasicConfigKey.builder(new
TypeToken<Entity>(){})
+            .name("test.reference.entity1a")
+            .build();    
+    @SuppressWarnings("serial")
     public static final ConfigKey<Entity> TEST_REFERENCE_ENTITY2 = BasicConfigKey.builder(new
TypeToken<Entity>(){})
             .name("test.reference.entity2")
             .build();
@@ -55,4 +59,8 @@ public interface ReferencingYamlTestEntity extends Entity {
     public static final ConfigKey<Entity> TEST_REFERENCE_GRANDCHILD2 = BasicConfigKey.builder(new
TypeToken<Entity>(){})
             .name("test.reference.grandchild2")
             .build(); 
+    @SuppressWarnings("serial")
+    public static final ConfigKey<Entity> TEST_REFERENCE_BOGUS = BasicConfigKey.builder(new
TypeToken<Entity>(){})
+            .name("test.reference.bogus")
+            .build(); 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/usage/camp/src/test/resources/test-referencing-entities.yaml
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/test-referencing-entities.yaml b/usage/camp/src/test/resources/test-referencing-entities.yaml
index 84a8d3f..7a5dfec 100644
--- a/usage/camp/src/test/resources/test-referencing-entities.yaml
+++ b/usage/camp/src/test/resources/test-referencing-entities.yaml
@@ -38,36 +38,43 @@ origin: http://brooklyn.io
 id: app1
 brooklyn.config:
   test.reference.app: $brooklyn:component("app1")
-  test.reference.entity1: $brooklyn:component("e1")
+  test.reference.entity1: $brooklyn:entity("e1")
+  test.reference.entity1a: $brooklyn:config("test.reference.entity1")
   test.reference.entity2: $brooklyn:component("e2")
   test.reference.child1: $brooklyn:component("c1")
   test.reference.child2: $brooklyn:component("c2")
   test.reference.grandchild1: $brooklyn:component("gc1")
   test.reference.grandchild2: $brooklyn:component("gc2")
+  test.reference.bogus: $brooklyn:child("c1")
 services:
 - serviceType: io.brooklyn.camp.brooklyn.ReferencingYamlTestEntity
   id: e1
   name: entity 1
   brooklyn.config:
-    test.reference.app: $brooklyn:component("app1")
-    test.reference.entity1: $brooklyn:component("e1")
+    test.reference.app: $brooklyn:component("parent", "ignored")
+    test.reference.entity1: $brooklyn:component("this", "ignored")
+    test.reference.entity1a: $brooklyn:ancestor("app1").child("e1")
     test.reference.entity2: $brooklyn:component("e2")
-    test.reference.child1: $brooklyn:component("c1")
+    test.reference.child1: $brooklyn:component("child", "c1")
     test.reference.child2: $brooklyn:component("c2")
     test.reference.grandchild1: $brooklyn:component("gc1")
     test.reference.grandchild2: $brooklyn:component("gc2")
+    test.reference.bogus: $brooklyn:descendant("app1")
   brooklyn.children:
     - serviceType: io.brooklyn.camp.brooklyn.ReferencingYamlTestEntity
       id: c1
       name: child 1
       brooklyn.config:
-        test.reference.app: $brooklyn:component("app1")
-        test.reference.entity1: $brooklyn:component("e1")
+        self: $brooklyn:entity("c1")
+        test.reference.app: $brooklyn:parent().parent()
+        test.reference.entity1: $brooklyn:parent()
+        test.reference.entity1a: $brooklyn:entity("e1").parent().child("e1")
         test.reference.entity2: $brooklyn:component("e2")
-        test.reference.child1: $brooklyn:component("c1")
+        test.reference.child1: $brooklyn:config("self")
         test.reference.child2: $brooklyn:component("c2")
         test.reference.grandchild1: $brooklyn:component("gc1")
         test.reference.grandchild2: $brooklyn:component("gc2")
+        test.reference.bogus: $brooklyn:component("bogus")
       brooklyn.children:
       - serviceType: io.brooklyn.camp.brooklyn.ReferencingYamlTestEntity
         id: gc1
@@ -95,7 +102,7 @@ services:
       id: c2
       name: child 2
       brooklyn.config:
-        test.reference.app: $brooklyn:component("app1")
+        test.reference.app: $brooklyn:parent().parent().descendant("app1")
         test.reference.entity1: $brooklyn:component("e1")
         test.reference.entity2: $brooklyn:component("e2")
         test.reference.child1: $brooklyn:component("c1")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
b/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
index f7b1dd0..0a5570d 100644
--- a/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
+++ b/utils/common/src/main/java/brooklyn/util/collections/CollectionFunctionals.java
@@ -19,6 +19,7 @@
 package brooklyn.util.collections;
 
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -130,4 +131,26 @@ public class CollectionFunctionals {
         return Predicates.compose(Predicates.equalTo(targetSize), CollectionFunctionals.<K>mapSize());
     }
 
+    public static <T,I extends Iterable<T>> Function<I, List<T>>
limit(final int max) {
+        return new LimitFunction<T,I>(max);
+    }
+
+    private static final class LimitFunction<T, I extends Iterable<T>> implements
Function<I, List<T>> {
+        private final int max;
+        private LimitFunction(int max) {
+            this.max = max;
+        }
+        @Override
+        public List<T> apply(I input) {
+            if (input==null) return null;
+            MutableList<T> result = MutableList.of();
+            for (T i: input) {
+                result.add(i);
+                if (result.size()>=max)
+                    return result;
+            }
+            return result;
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c6d6cc4a/utils/common/src/main/java/brooklyn/util/guava/Functionals.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/guava/Functionals.java b/utils/common/src/main/java/brooklyn/util/guava/Functionals.java
index ef66ded..6688bab 100644
--- a/utils/common/src/main/java/brooklyn/util/guava/Functionals.java
+++ b/utils/common/src/main/java/brooklyn/util/guava/Functionals.java
@@ -18,6 +18,8 @@
  */
 package brooklyn.util.guava;
 
+import java.util.concurrent.Callable;
+
 import brooklyn.util.guava.IfFunctions.IfFunctionBuilderApplyingFirst;
 
 import com.google.common.base.Function;
@@ -111,4 +113,14 @@ public class Functionals {
         return new SupplierAsRunnable();
     }
 
+    public static <T> Callable<T> callable(final Supplier<T> supplier)
{
+        class SupplierAsCallable implements Callable<T> {
+            @Override
+            public T call() {
+                return supplier.get();
+            }
+        }
+        return new SupplierAsCallable();
+    }
+
 }


Mime
View raw message