Change conditional entity to reflect service state of optional child

Propagate value for service.isUp and optional configurable set of sensors


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

Branch: refs/heads/master
Commit: ec3010e412440e3a20e2f5e973e0774335990546
Parents: b73cb73
Author: Andrew Donald Kennedy <[email protected]>
Authored: Wed Aug 10 18:24:45 2016 +0100
Committer: Andrew Donald Kennedy <[email protected]>
Committed: Sat Aug 20 17:15:13 2016 +0100

----------------------------------------------------------------------
 .../entity/stock/ConditionalEntity.java         | 23 +++++-
 .../entity/stock/ConditionalEntityImpl.java     | 82 +++++++++++++++++---
 .../entity/stock/ConditionalEntityTest.java     | 33 +++++++-
 3 files changed, 124 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ec3010e4/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java 
b/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java
index 0e0a112..c5f8d81 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntity.java
@@ -18,6 +18,8 @@
  */
 package org.apache.brooklyn.entity.stock;
 
+import java.util.Collection;
+
 import com.google.common.annotations.Beta;
 import com.google.common.reflect.TypeToken;
 
@@ -44,6 +46,10 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag;
  *         brooklyn.config:
  *           proxy.port: 8080
  *           loadbalancer.serverpool: $brooklyn:entity("servers")
+ *     conditional.entity.propagate: true
+ *     conditional.entity.sensors:
+ *       - $brooklyn:sensor("proxy.http.port")
+ *       - $brooklyn:sensor("main.uri")
  * </pre>
  */
 @Beta
@@ -51,11 +57,22 @@ import org.apache.brooklyn.util.core.flags.SetFromFlag;
 public interface ConditionalEntity extends BasicStartable {
 
     @SetFromFlag("entitySpec")
-    ConfigKey<EntitySpec<?>> CONDITIONAL_ENTITY_SPEC = 
ConfigKeys.newConfigKey(new TypeToken<EntitySpec<?>>() { }, 
"conditional.entity.spec", "The entity specification to be created");
+    ConfigKey<EntitySpec<?>> CONDITIONAL_ENTITY_SPEC = 
ConfigKeys.newConfigKey(new TypeToken<EntitySpec<?>>() { },
+            "conditional.entity.spec", "The entity specification to be 
created");
 
     @SetFromFlag("create")
-    AttributeSensorAndConfigKey<Boolean, Boolean> CREATE_CONDITIONAL_ENTITY = 
ConfigKeys.newSensorAndConfigKey(Boolean.class, "conditional.entity.create", 
"Whether the entity should be created");
+    AttributeSensorAndConfigKey<Boolean, Boolean> CREATE_CONDITIONAL_ENTITY = 
ConfigKeys.newSensorAndConfigKey(Boolean.class,
+            "conditional.entity.create", "Whether the entity should be 
created");
+
+    @SetFromFlag("propagateSensors")
+    ConfigKey<Boolean> PROPAGATE_CONDITIONAL_ENTITY_SENSORS = 
ConfigKeys.newBooleanConfigKey(
+            "conditional.entity.propagate", "Whether sensors are to be 
propagated from the child entity", Boolean.TRUE);
+
+    @SetFromFlag("sensorsToPropagate")
+    ConfigKey<Collection<AttributeSensor<?>>> CONDITIONAL_ENTITY_SENSOR_LIST = 
ConfigKeys.newConfigKey(new TypeToken<Collection<AttributeSensor<?>>>() { },
+            "conditional.entity.sensors", "Collection of sensors that are to 
be propagated from the child entity (all usual sensors if not set, or empty)");
 
-    AttributeSensor<Entity> CONDITIONAL_ENTITY = 
Sensors.newSensor(Entity.class, "conditional.entity", "The created entity");
+    AttributeSensor<Entity> CONDITIONAL_ENTITY = 
Sensors.newSensor(Entity.class,
+            "conditional.entity", "The created entity");
 
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ec3010e4/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java
 
b/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java
index 6c73a87..054b5b0 100644
--- 
a/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java
+++ 
b/core/src/main/java/org/apache/brooklyn/entity/stock/ConditionalEntityImpl.java
@@ -19,26 +19,88 @@
 package org.apache.brooklyn.entity.stock;
 
 import java.util.Collection;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
+import org.apache.brooklyn.core.entity.trait.Startable;
+import org.apache.brooklyn.core.location.Locations;
+import org.apache.brooklyn.enricher.stock.Enrichers;
+import org.apache.brooklyn.util.collections.MutableSet;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.time.Duration;
 
 public class ConditionalEntityImpl extends BasicStartableImpl implements 
ConditionalEntity {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(BasicStartableImpl.class);
+
     @Override
     public void start(Collection<? extends Location> locations) {
-        Entity child = sensors().get(CONDITIONAL_ENTITY);
-        EntitySpec<?> spec = config().get(CONDITIONAL_ENTITY_SPEC);
-        Boolean create = config().get(CREATE_CONDITIONAL_ENTITY);
-
-        // Child not yet created; Entity spec is present; Create flag is true
-        if (child == null && spec != null && Boolean.TRUE.equals(create)) {
-            Entity created = addChild(EntitySpec.create(spec));
-            sensors().set(CONDITIONAL_ENTITY, created);
+        try {
+            ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
+            sensors().set(Attributes.SERVICE_UP, false);
+
+            // Block startup until other dependent components are available
+            Object val = config().get(START_LATCH);
+            if (val != null) {
+                LOG.debug("Finished waiting for start-latch in {}", this);
+            }
+
+            Entity child = sensors().get(CONDITIONAL_ENTITY);
+            EntitySpec<?> spec = config().get(CONDITIONAL_ENTITY_SPEC);
+            Boolean create = config().get(CREATE_CONDITIONAL_ENTITY);
+            Boolean propagate = 
config().get(PROPAGATE_CONDITIONAL_ENTITY_SENSORS);
+            Set<AttributeSensor<?>> sensors = 
MutableSet.copyOf(config().get(CONDITIONAL_ENTITY_SENSOR_LIST));
+            Duration timeout = config().get(BrooklynConfigKeys.START_TIMEOUT);
+
+            addLocations(locations);
+            locations = Locations.getLocationsCheckingAncestors(locations, 
this);
+            LOG.info("Starting entity {}: {}", this, locations);
+
+            // Child not yet created; Entity spec is present; Create flag is 
true
+            if (child == null && spec != null && Boolean.TRUE.equals(create)) {
+                child = addChild(EntitySpec.create(spec));
+                sensors().set(CONDITIONAL_ENTITY, child);
+
+                // Add enrichers for sensor propagateion
+                
enrichers().add(Enrichers.builder().propagating(Startable.SERVICE_UP).from(child).build());
+                if (Boolean.TRUE.equals(propagate)) {
+                    if (sensors.isEmpty()) {
+                        
enrichers().add(Enrichers.builder().propagatingAllButUsualAnd().from(child).build());
+                    } else {
+                        
enrichers().add(Enrichers.builder().propagating(sensors).from(child).build());
+                    }
+                }
+            }
+
+            // Start child if create flag is set; otherwise just set 
service.isUp
+            if (Boolean.TRUE.equals(create)) {
+                LOG.info("Starting child {}: {}", child, locations);
+                if (Entities.invokeEffectorWithArgs(this, child, 
Startable.START, locations).blockUntilEnded(timeout)) {
+                    LOG.debug("Successfully started {} by {}", child, this);
+                } else {
+                    throw new IllegalStateException(String.format("Timed out 
while %s was starting %s", this, child));
+                }
+            } else {
+                LOG.debug("No child created, setting SERVICE_UP to true");
+                sensors().set(Attributes.SERVICE_UP, true);
+            }
+
+            ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
+        } catch (Throwable t) {
+            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
+            throw Exceptions.propagate(t);
         }
-        super.start(locations);
     }
-
 }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ec3010e4/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java
 
b/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java
index 0e1a56e..7ef837c 100644
--- 
a/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/entity/stock/ConditionalEntityTest.java
@@ -19,17 +19,21 @@
 package org.apache.brooklyn.entity.stock;
 
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.*;
 
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.location.SimulatedLocation;
 import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.TestEntity;
@@ -57,6 +61,33 @@ public class ConditionalEntityTest extends 
BrooklynAppUnitTestSupport {
         Entity child = Iterables.getOnlyElement(optional.getChildren());
         assertTrue(child instanceof TestEntity);
         assertEquals(child, 
optional.sensors().get(ConditionalEntity.CONDITIONAL_ENTITY));
+
+        // The service.isUp sensor will have been propagated by default
+        EntityAsserts.assertAttributeEqualsEventually(child, 
Startable.SERVICE_UP, true);
+        EntityAsserts.assertAttributeEqualsEventually(optional, 
Startable.SERVICE_UP, true);
+    }
+
+    @Test
+    public void testAddsConditionalAndPropagatesSensors() throws Exception {
+        optional = app.addChild(EntitySpec.create(ConditionalEntity.class)
+                .configure(ConditionalEntity.CREATE_CONDITIONAL_ENTITY, true)
+                
.configure(ConditionalEntity.PROPAGATE_CONDITIONAL_ENTITY_SENSORS, true)
+                .configure(ConditionalEntity.CONDITIONAL_ENTITY_SENSOR_LIST, 
ImmutableList.<AttributeSensor<?>>of(TestEntity.SEQUENCE))
+                .configure(ConditionalEntity.CONDITIONAL_ENTITY_SPEC, 
EntitySpec.create(TestEntity.class)));
+        app.start(ImmutableList.of(loc1));
+
+        assertEquals(optional.getChildren().size(), 1);
+        Entity child = Iterables.getOnlyElement(optional.getChildren());
+        assertTrue(child instanceof TestEntity);
+        assertEquals(child, 
optional.sensors().get(ConditionalEntity.CONDITIONAL_ENTITY));
+
+        // Check that the configured sensors are propagated
+        child.sensors().set(TestEntity.SEQUENCE, 123);
+        EntityAsserts.assertAttributeEqualsEventually(child, 
TestEntity.SEQUENCE, 123);
+        EntityAsserts.assertAttributeEqualsEventually(optional, 
TestEntity.SEQUENCE, 123);
+        child.sensors().set(TestEntity.NAME, "frog");
+        EntityAsserts.assertAttributeEqualsEventually(child, TestEntity.NAME, 
"frog");
+        EntityAsserts.assertAttribute(optional, TestEntity.NAME, 
Predicates.isNull());
     }
 
     @Test

Reply via email to