Coerce aggregated values, might be coming from string sources Caller code expects values to be in the sensor type, coerce the values before returning them. String values could be inserted - for example from BrooklynEntityMirror.
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/2a6d9fd5 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/2a6d9fd5 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/2a6d9fd5 Branch: refs/heads/master Commit: 2a6d9fd566f90a4fb8e6f67815d9e50f7bb78e63 Parents: ff31a41 Author: Svetoslav Neykov <[email protected]> Authored: Tue Apr 21 17:10:16 2015 +0300 Committer: Svetoslav Neykov <[email protected]> Committed: Wed Apr 22 14:50:00 2015 +0300 ---------------------------------------------------------------------- .../basic/AbstractMultipleSensorAggregator.java | 22 +++++++++++-- .../entity/basic/ServiceStateLogicTest.java | 34 +++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a6d9fd5/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java b/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java index b40c234..793d8a9 100644 --- a/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java +++ b/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java @@ -20,8 +20,10 @@ package brooklyn.enricher.basic; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Map.Entry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +35,7 @@ import brooklyn.event.Sensor; import brooklyn.event.SensorEvent; import brooklyn.event.SensorEventListener; import brooklyn.util.collections.MutableMap; +import brooklyn.util.flags.TypeCoercions; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; @@ -138,11 +141,26 @@ public abstract class AbstractMultipleSensorAggregator<U> extends AbstractAggreg onUpdated(); } - @SuppressWarnings("unchecked") public <T> Map<Entity,T> getValues(Sensor<T> sensor) { + Map<Entity, T> valuesCopy = copyValues(sensor); + return coerceValues(valuesCopy, sensor.getType()); + } + + private <T> Map<Entity, T> coerceValues(Map<Entity, T> values, Class<? super T> type) { + Map<Entity, T> typedValues = MutableMap.of(); + for (Entry<Entity, T> entry : values.entrySet()) { + @SuppressWarnings("unchecked") + T typedValue = (T) TypeCoercions.coerce(entry.getValue(), type); + typedValues.put(entry.getKey(), typedValue); + } + return typedValues; + } + + private <T> Map<Entity, T> copyValues(Sensor<T> sensor) { synchronized (values) { + @SuppressWarnings("unchecked") Map<Entity, T> sv = (Map<Entity, T>) values.get(sensor.getName()); - if (sv==null) return ImmutableMap.of(); + //use MutableMap because of potentially null values return MutableMap.copyOf(sv).asUnmodifiable(); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a6d9fd5/core/src/test/java/brooklyn/entity/basic/ServiceStateLogicTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/entity/basic/ServiceStateLogicTest.java b/core/src/test/java/brooklyn/entity/basic/ServiceStateLogicTest.java index 00dd322..d30b05a 100644 --- a/core/src/test/java/brooklyn/entity/basic/ServiceStateLogicTest.java +++ b/core/src/test/java/brooklyn/entity/basic/ServiceStateLogicTest.java @@ -24,16 +24,22 @@ import org.testng.annotations.Test; import brooklyn.entity.BrooklynAppUnitTestSupport; import brooklyn.entity.Entity; +import brooklyn.entity.Group; +import brooklyn.entity.basic.EntitySubscriptionTest.RecordingSensorEventListener; import brooklyn.entity.basic.QuorumCheck.QuorumChecks; import brooklyn.entity.basic.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers; import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic; import brooklyn.entity.basic.ServiceStateLogic.ServiceProblemsLogic; +import brooklyn.entity.group.DynamicCluster; import brooklyn.entity.proxying.EntitySpec; import brooklyn.event.AttributeSensor; +import brooklyn.event.basic.Sensors; import brooklyn.location.Location; +import brooklyn.location.basic.SimulatedLocation; import brooklyn.policy.Enricher; import brooklyn.test.EntityTestUtils; import brooklyn.test.entity.TestEntity; +import brooklyn.test.entity.TestEntityImpl.TestEntityWithoutEnrichers; import brooklyn.util.exceptions.Exceptions; import brooklyn.util.time.Duration; @@ -240,7 +246,33 @@ public class ServiceStateLogicTest extends BrooklynAppUnitTestSupport { assertAttributeEquals(entity, Attributes.SERVICE_UP, true); assertAttributeEquals(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); } - + + @Test + public void testQuorumWithStringStates() { + final DynamicCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class) + .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(TestEntityWithoutEnrichers.class)) + .configure(DynamicCluster.INITIAL_SIZE, 1)); + + RecordingSensorEventListener r = new RecordingSensorEventListener(); + app.subscribe(cluster, Attributes.SERVICE_STATE_ACTUAL, r); + + cluster.start(ImmutableList.of(new SimulatedLocation())); + EntityTestUtils.assertGroupSizeEqualsEventually(cluster, 1); + + //manually set state to healthy as enrichers are disabled + EntityInternal child = (EntityInternal) cluster.getMembers().iterator().next(); + child.setAttribute(Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); + child.setAttribute(Attributes.SERVICE_UP, Boolean.TRUE); + + EntityTestUtils.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); + + //set untyped service state, the quorum check should be able to handle coercion + AttributeSensor<Object> stateSensor = Sensors.newSensor(Object.class, Attributes.SERVICE_STATE_ACTUAL.getName()); + child.setAttribute(stateSensor, "running"); + + EntityTestUtils.assertAttributeEqualsContinually(cluster, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); + } + private static <T> void assertAttributeEqualsEventually(Entity x, AttributeSensor<T> sensor, T value) { try { EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", Duration.seconds(3)), x, sensor, value);
