Repository: incubator-brooklyn Updated Branches: refs/heads/master fa131b105 -> b73c05b57
adds formatString function Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/8cf510cb Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/8cf510cb Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/8cf510cb Branch: refs/heads/master Commit: 8cf510cb872c0ec85998e9853cb01a815ebecd27 Parents: f0ca574 Author: Robert Moss <[email protected]> Authored: Wed Sep 23 14:16:47 2015 +0100 Committer: Robert Moss <[email protected]> Committed: Thu Oct 1 16:37:52 2015 +0100 ---------------------------------------------------------------------- .../brooklyn/enricher/stock/Enrichers.java | 1 + .../apache/brooklyn/enricher/stock/Reducer.java | 162 ------------- .../stock/reducer/GenericStringReducer.java | 21 ++ .../stock/reducer/ObjectStringReducer.java | 19 ++ .../enricher/stock/reducer/Reducer.java | 163 +++++++++++++ .../stock/reducer/StringStringReducer.java | 23 ++ .../brooklyn/enricher/stock/ReducerTest.java | 216 ----------------- .../enricher/stock/reducer/ReducerTest.java | 237 +++++++++++++++++++ 8 files changed, 464 insertions(+), 378 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8cf510cb/core/src/main/java/org/apache/brooklyn/enricher/stock/Enrichers.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Enrichers.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Enrichers.java index 25d186f..8c73653 100644 --- a/core/src/main/java/org/apache/brooklyn/enricher/stock/Enrichers.java +++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Enrichers.java @@ -33,6 +33,7 @@ import org.apache.brooklyn.api.sensor.EnricherSpec; import org.apache.brooklyn.api.sensor.Sensor; import org.apache.brooklyn.api.sensor.SensorEvent; import org.apache.brooklyn.core.enricher.AbstractEnricher; +import org.apache.brooklyn.enricher.stock.reducer.Reducer; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.MutableSet; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8cf510cb/core/src/main/java/org/apache/brooklyn/enricher/stock/Reducer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Reducer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Reducer.java deleted file mode 100644 index 938cf22..0000000 --- a/core/src/main/java/org/apache/brooklyn/enricher/stock/Reducer.java +++ /dev/null @@ -1,162 +0,0 @@ -package org.apache.brooklyn.enricher.stock; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.api.sensor.SensorEventListener; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.enricher.AbstractEnricher; -import org.apache.brooklyn.util.core.flags.SetFromFlag; -import org.apache.brooklyn.util.core.task.Tasks; -import org.apache.brooklyn.util.core.task.ValueResolver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.api.client.util.Lists; -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.reflect.TypeToken; - -@SuppressWarnings("serial") -public abstract class Reducer<S, T> extends AbstractEnricher implements SensorEventListener<Object> { - - private static final Logger LOG = LoggerFactory.getLogger(Reducer.class); - - @SetFromFlag("producer") - public static ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer"); - public static ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor"); - public static ConfigKey<List<? extends AttributeSensor<?>>> SOURCE_SENSORS = ConfigKeys.newConfigKey(new TypeToken<List<? extends AttributeSensor<?>>>() {}, "enricher.sourceSensors"); - public static ConfigKey<Function<List<?>,?>> REDUCER_FUNCTION = ConfigKeys.newConfigKey(new TypeToken<Function<List<?>, ?>>() {}, "enricher.reducerFunction"); - @SetFromFlag("transformation") - public static final ConfigKey<String> REDUCER_FUNCTION_UNTYPED = ConfigKeys.newStringConfigKey("enricher.reducerFunction.untyped", - "A string matching a pre-defined named reducer function, such as join"); - public static final ConfigKey<Map<String, Object>> PARAMETERS = ConfigKeys.newConfigKey(new TypeToken<Map<String, Object>>() {}, "enricher.reducerFunctionParameters", - "A map of parameters to pass into the reducer function"); - - protected Entity producer; - protected List<AttributeSensor<S>> subscribedSensors; - protected Sensor<T> targetSensor; - protected Function<List<S>, T> reducerFunction; - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public void setEntity(EntityLocal entity) { - super.setEntity(entity); - Preconditions.checkNotNull(getConfig(SOURCE_SENSORS), "source sensors"); - - this.producer = getConfig(PRODUCER) == null ? entity : getConfig(PRODUCER); - List<AttributeSensor<S>> sensorListTemp = Lists.newArrayList(); - - for (Object sensorO : getConfig(SOURCE_SENSORS)) { - AttributeSensor<S> sensor = Tasks.resolving(sensorO).as(AttributeSensor.class).timeout(ValueResolver.REAL_QUICK_WAIT).context(producer).get(); - if(!sensorListTemp.contains(sensor)) { - sensorListTemp.add(sensor); - } - } - - String reducerName = config().get(REDUCER_FUNCTION_UNTYPED); - Function<List<S>, T> reducerFunction = (Function) config().get(REDUCER_FUNCTION); - if(reducerFunction == null){ - Map<String, ?> parameters = config().get(PARAMETERS); - reducerFunction = createReducerFunction(reducerName, parameters); - } - - this.reducerFunction = reducerFunction; - Preconditions.checkState(sensorListTemp.size() > 0, "Nothing to reduce"); - - for (Sensor<S> sensor : sensorListTemp) { - subscribe(producer, sensor, this); - } - - subscribedSensors = ImmutableList.copyOf(sensorListTemp); - } - - protected abstract Function<List<S>, T> createReducerFunction(String reducerName, Map<String, ?> parameters); - - @SuppressWarnings("unchecked") - @Override - public void onEvent(SensorEvent<Object> event) { - Sensor<T> destinationSensor = (Sensor<T>) getConfig(TARGET_SENSOR); - - List<S> values = Lists.newArrayList(); - - for (AttributeSensor<S> sourceSensor : subscribedSensors) { - S resolvedSensorValue = entity.sensors().get(sourceSensor); - if (resolvedSensorValue == null) { - // only apply function if all values are resolved - return; - } - - values.add(resolvedSensorValue); - } - - Object result = reducerFunction.apply(values); - - if (LOG.isTraceEnabled()) LOG.trace("enricher {} got {}, propagating via {} as {}", - new Object[] {this, event, entity, reducerFunction, destinationSensor}); - - emit((Sensor<T>)destinationSensor, result); - } - - public static class StringStringReducer extends Reducer<String, String> { - - public StringStringReducer() {} - - @Override - protected Function<List<String>, String> createReducerFunction( - String reducerName, Map<String, ?> parameters) { - if(reducerName.equals("joiner")){ - return new JoinerFunction(parameters.get("separator")); - } - throw new IllegalStateException("unknown function: " + reducerName); - } - } - - public static class JoinerReducerFunction<A> implements Function<List<A>, String> { - - private Object separator; - - public JoinerReducerFunction(Object separator) { - this.separator = (separator == null) ? ", " : separator; - } - - @Override - public String apply(List<A> input) { - - StringBuilder sb = new StringBuilder(); - Iterator<A> it = input.iterator(); - while(it.hasNext()) { - sb.append(it.next().toString()); - if(it.hasNext()){ - sb.append(separator); - } - } - return sb.toString(); - } - - } - - public static class JoinerFunction extends JoinerReducerFunction<String>{ - - public JoinerFunction(Object separator) { - super(separator); - } - } - - public static class ToStringReducerFunction<A> implements Function<List<A>, String> { - - @Override - public String apply(List<A> input) { - return input.toString(); - } - - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8cf510cb/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/GenericStringReducer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/GenericStringReducer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/GenericStringReducer.java new file mode 100644 index 0000000..037a869 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/GenericStringReducer.java @@ -0,0 +1,21 @@ +package org.apache.brooklyn.enricher.stock.reducer; + +import java.util.List; +import java.util.Map; + +import com.google.common.base.Function; +import com.google.common.base.Preconditions; + +public abstract class GenericStringReducer<T> extends Reducer<T, String>{ + + @Override + protected Function<List<T>, String> createReducerFunction( + String reducerName, Map<String, ?> parameters) { + if (reducerName.equals("formatString")){ + String format = Preconditions.checkNotNull((String)parameters.get("format"), "format"); + return new FormatStringReducerFunction<T>(format); + } + return null; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8cf510cb/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/ObjectStringReducer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/ObjectStringReducer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/ObjectStringReducer.java new file mode 100644 index 0000000..775d075 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/ObjectStringReducer.java @@ -0,0 +1,19 @@ +package org.apache.brooklyn.enricher.stock.reducer; + +import java.util.List; +import java.util.Map; + +import com.google.common.base.Function; + +public class ObjectStringReducer extends GenericStringReducer<Object> { + + @Override + protected Function<List<Object>, String> createReducerFunction( + String reducerName, Map<String, ?> parameters) { + + Function<List<Object>, String> function = super.createReducerFunction(reducerName, parameters); + if(function != null) return function; + + throw new IllegalStateException("unknown function: " + reducerName); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8cf510cb/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java new file mode 100644 index 0000000..439b003 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java @@ -0,0 +1,163 @@ +package org.apache.brooklyn.enricher.stock.reducer; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.entity.EntityLocal; +import org.apache.brooklyn.api.sensor.AttributeSensor; +import org.apache.brooklyn.api.sensor.Sensor; +import org.apache.brooklyn.api.sensor.SensorEvent; +import org.apache.brooklyn.api.sensor.SensorEventListener; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.enricher.AbstractEnricher; +import org.apache.brooklyn.util.core.flags.SetFromFlag; +import org.apache.brooklyn.util.core.task.Tasks; +import org.apache.brooklyn.util.core.task.ValueResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.api.client.util.Lists; +import com.google.common.base.Function; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; + +@SuppressWarnings("serial") +public abstract class Reducer<S, T> extends AbstractEnricher implements SensorEventListener<Object> { + + private static final Logger LOG = LoggerFactory.getLogger(Reducer.class); + + @SetFromFlag("producer") + public static ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer"); + public static ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor"); + public static ConfigKey<List<? extends AttributeSensor<?>>> SOURCE_SENSORS = ConfigKeys.newConfigKey(new TypeToken<List<? extends AttributeSensor<?>>>() {}, "enricher.sourceSensors"); + public static ConfigKey<Function<List<?>,?>> REDUCER_FUNCTION = ConfigKeys.newConfigKey(new TypeToken<Function<List<?>, ?>>() {}, "enricher.reducerFunction"); + @SetFromFlag("transformation") + public static final ConfigKey<String> REDUCER_FUNCTION_UNTYPED = ConfigKeys.newStringConfigKey("enricher.reducerFunction.untyped", + "A string matching a pre-defined named reducer function, such as join"); + public static final ConfigKey<Map<String, Object>> PARAMETERS = ConfigKeys.newConfigKey(new TypeToken<Map<String, Object>>() {}, "enricher.reducerFunction.parameters", + "A map of parameters to pass into the reducer function"); + + protected Entity producer; + protected List<AttributeSensor<S>> subscribedSensors; + protected Sensor<T> targetSensor; + protected Function<List<S>, T> reducerFunction; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void setEntity(EntityLocal entity) { + super.setEntity(entity); + Preconditions.checkNotNull(getConfig(SOURCE_SENSORS), "source sensors"); + + this.producer = getConfig(PRODUCER) == null ? entity : getConfig(PRODUCER); + List<AttributeSensor<S>> sensorListTemp = Lists.newArrayList(); + + for (Object sensorO : getConfig(SOURCE_SENSORS)) { + AttributeSensor<S> sensor = Tasks.resolving(sensorO).as(AttributeSensor.class).timeout(ValueResolver.REAL_QUICK_WAIT).context(producer).get(); + if(!sensorListTemp.contains(sensor)) { + sensorListTemp.add(sensor); + } + } + + String reducerName = config().get(REDUCER_FUNCTION_UNTYPED); + Function<List<S>, T> reducerFunction = (Function) config().get(REDUCER_FUNCTION); + if(reducerFunction == null){ + Map<String, ?> parameters = config().get(PARAMETERS); + reducerFunction = createReducerFunction(reducerName, parameters); + } + + this.reducerFunction = reducerFunction; + Preconditions.checkState(sensorListTemp.size() > 0, "Nothing to reduce"); + + for (Sensor<S> sensor : sensorListTemp) { + subscribe(producer, sensor, this); + } + + subscribedSensors = ImmutableList.copyOf(sensorListTemp); + } + + protected abstract Function<List<S>, T> createReducerFunction(String reducerName, Map<String, ?> parameters); + + @SuppressWarnings("unchecked") + @Override + public void onEvent(SensorEvent<Object> event) { + Sensor<T> destinationSensor = (Sensor<T>) getConfig(TARGET_SENSOR); + + List<S> values = Lists.newArrayList(); + + for (AttributeSensor<S> sourceSensor : subscribedSensors) { + S resolvedSensorValue = entity.sensors().get(sourceSensor); + if (resolvedSensorValue == null) { + // only apply function if all values are resolved + return; + } + + values.add(resolvedSensorValue); + } + + Object result = reducerFunction.apply(values); + + if (LOG.isTraceEnabled()) LOG.trace("enricher {} got {}, propagating via {} as {}", + new Object[] {this, event, entity, reducerFunction, destinationSensor}); + + emit((Sensor<T>)destinationSensor, result); + } + + public static class JoinerReducerFunction<A> implements Function<List<A>, String> { + + private Object separator; + + public JoinerReducerFunction(Object separator) { + this.separator = (separator == null) ? ", " : separator; + } + + @Override + public String apply(List<A> input) { + + StringBuilder sb = new StringBuilder(); + Iterator<A> it = input.iterator(); + while(it.hasNext()) { + sb.append(it.next().toString()); + if(it.hasNext()){ + sb.append(separator); + } + } + return sb.toString(); + } + + } + + public static class JoinerFunction extends JoinerReducerFunction<String>{ + + public JoinerFunction(Object separator) { + super(separator); + } + } + + public static class ToStringReducerFunction<A> implements Function<List<A>, String> { + + @Override + public String apply(List<A> input) { + return input.toString(); + } + + } + + public static class FormatStringReducerFunction<T> implements Function<List<T>, String> { + + private String format; + + public FormatStringReducerFunction(String format) { + this.format = Preconditions.checkNotNull(format, "format"); + } + + @Override + public String apply(List<T> input) { + return String.format(format, input.toArray()); + } + + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8cf510cb/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/StringStringReducer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/StringStringReducer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/StringStringReducer.java new file mode 100644 index 0000000..eaa0dc7 --- /dev/null +++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/StringStringReducer.java @@ -0,0 +1,23 @@ +package org.apache.brooklyn.enricher.stock.reducer; + +import java.util.List; +import java.util.Map; + +import com.google.common.base.Function; + +public class StringStringReducer extends GenericStringReducer<String> { + + public StringStringReducer() {} + + @Override + protected Function<List<String>, String> createReducerFunction( + String reducerName, Map<String, ?> parameters) { + Function<List<String>, String> function = super.createReducerFunction(reducerName, parameters); + if(function != null) return function; + + if(reducerName.equals("joiner")){ + return new JoinerFunction(parameters.get("separator")); + } + throw new IllegalStateException("unknown function: " + reducerName); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8cf510cb/core/src/test/java/org/apache/brooklyn/enricher/stock/ReducerTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/ReducerTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/ReducerTest.java deleted file mode 100644 index a39d76c..0000000 --- a/core/src/test/java/org/apache/brooklyn/enricher/stock/ReducerTest.java +++ /dev/null @@ -1,216 +0,0 @@ -package org.apache.brooklyn.enricher.stock; - -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; - -import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.EnricherSpec; -import org.apache.brooklyn.core.sensor.Sensors; -import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; -import org.apache.brooklyn.core.test.entity.TestEntity; -import org.apache.brooklyn.enricher.stock.Reducer.StringStringReducer; -import org.apache.brooklyn.test.Asserts; -import org.apache.brooklyn.test.EntityTestUtils; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.testng.Assert; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -public class ReducerTest extends BrooklynAppUnitTestSupport { - - public static final AttributeSensor<String> STR1 = Sensors.newStringSensor("test.str1"); - public static final AttributeSensor<String> STR2 = Sensors.newStringSensor("test.str2"); - public static final AttributeSensor<String> STR3 = Sensors.newStringSensor("test.str3"); - public static final AttributeSensor<Integer> INT1 = Sensors.newIntegerSensor("test.int1"); - - private TestEntity entity; - - @BeforeMethod(alwaysRun=true) - @Override - public void setUp() throws Exception { - super.setUp(); - entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)); - } - - @Test - public void testBasicReducer(){ - entity.addEnricher(EnricherSpec.create(StringStringReducer.class).configure( - MutableMap.of( - Reducer.SOURCE_SENSORS, ImmutableList.of(STR1, STR2), - Reducer.PRODUCER, entity, - Reducer.TARGET_SENSOR, STR3, - Reducer.REDUCER_FUNCTION, new Concatenator()) - ) - ); - - EntityTestUtils.assertAttributeEquals(entity, STR3, null); - - entity.sensors().set(STR1, "foo"); - EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); - - entity.sensors().set(STR2, "bar"); - EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foobar"); - } - - @Test - public void testReducingBuilderWithConcatenator() { - entity.addEnricher(Enrichers.builder() - .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) - .from(entity) - .computing(new Concatenator()) - .publishing(STR3) - .build() - ); - - EntityTestUtils.assertAttributeEquals(entity, STR3, null); - - entity.sensors().set(STR1, "foo"); - EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); - - entity.sensors().set(STR2, "bar"); - EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foobar"); - } - - @Test - public void testReducingBuilderWithLengthCalculator() { - entity.addEnricher(Enrichers.builder() - .reducing(StringIntegerReducer.class, ImmutableList.of(STR1, STR2)) - .from(entity) - .computing(new LengthCalculator()) - .publishing(INT1) - .build() - ); - - EntityTestUtils.assertAttributeEquals(entity, INT1, null); - - entity.sensors().set(STR1, "foo"); - EntityTestUtils.assertAttributeEqualsContinually(entity, INT1, null); - - entity.sensors().set(STR2, "bar"); - EntityTestUtils.assertAttributeEqualsEventually(entity, INT1, 6); - } - - @Test - public void testReducingBuilderWithJoinerFunction() { - entity.addEnricher(Enrichers.builder() - .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) - .from(entity) - .computing("joiner", ImmutableMap.<String, Object>of("separator", "-")) - .publishing(STR3) - .build() - ); - - EntityTestUtils.assertAttributeEquals(entity, STR3, null); - - entity.sensors().set(STR1, "foo"); - EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); - - entity.sensors().set(STR2, "bar"); - EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foo-bar"); - } - - @Test - public void testReducingBuilderWithJoinerFunctionWithDefaultParameter() { - entity.addEnricher(Enrichers.builder() - .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) - .from(entity) - .computing("joiner") - .publishing(STR3) - .build() - ); - EntityTestUtils.assertAttributeEquals(entity, STR3, null); - - entity.sensors().set(STR1, "foo"); - EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); - - entity.sensors().set(STR2, "bar"); - EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foo, bar"); - } - - @Test - public void testReducingBuilderWithJoinerFunctionAndUnusedParameter() { - - entity.addEnricher(Enrichers.builder() - .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) - .from(entity) - .computing("joiner", ImmutableMap.<String, Object>of("non.existent.parameter", "-")) - .publishing(STR3) - .build() - ); - EntityTestUtils.assertAttributeEquals(entity, STR3, null); - - entity.sensors().set(STR1, "foo"); - EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); - - entity.sensors().set(STR2, "bar"); - EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foo, bar"); - } - - @Test - public void testReducingBuilderWithNamedNonExistentFunction() { - try { - entity.addEnricher(Enrichers.builder() - .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) - .from(entity) - .computing("unknown function name", ImmutableMap.<String, Object>of("separator", "-")) - .publishing(STR3) - .build() - ); - Asserts.fail("Expected exception when adding reducing enricher with unknown named function"); - } catch (Exception e) { - Throwable t = Exceptions.getFirstThrowableOfType(e, IllegalStateException.class); - Assert.assertNotNull(t); - } - } - - private static class Concatenator implements Function<List<String>, String> { - @Nullable - @Override - public String apply(List<String> values) { - StringBuilder result = new StringBuilder(); - for (String value : values) { - if (value == null) { - return null; - } else { - result.append(value); - } - } - return result.toString(); - } - } - - public static class StringIntegerReducer extends Reducer<String, Integer> { - - public StringIntegerReducer() {} - - @Override - protected Function<List<String>, Integer> createReducerFunction( - String reducerName, Map<String, ?> parameters) { - throw new IllegalStateException("unknown function: " + reducerName); - } - - } - - private static class LengthCalculator implements Function<List<String>, Integer>{ - - @Override - public Integer apply(List<String> values) { - int acc = 0; - for (String value : values) { - if (value != null) { - acc += value.length(); - } - } - return acc; - } - - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8cf510cb/core/src/test/java/org/apache/brooklyn/enricher/stock/reducer/ReducerTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/reducer/ReducerTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/reducer/ReducerTest.java new file mode 100644 index 0000000..a1429f4 --- /dev/null +++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/reducer/ReducerTest.java @@ -0,0 +1,237 @@ +package org.apache.brooklyn.enricher.stock.reducer; + +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.sensor.AttributeSensor; +import org.apache.brooklyn.api.sensor.EnricherSpec; +import org.apache.brooklyn.core.sensor.Sensors; +import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; +import org.apache.brooklyn.core.test.entity.TestEntity; +import org.apache.brooklyn.enricher.stock.Enrichers; +import org.apache.brooklyn.enricher.stock.reducer.Reducer; +import org.apache.brooklyn.enricher.stock.reducer.StringStringReducer; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.test.EntityTestUtils; +import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class ReducerTest extends BrooklynAppUnitTestSupport { + + public static final AttributeSensor<String> STR1 = Sensors.newStringSensor("test.str1"); + public static final AttributeSensor<String> STR2 = Sensors.newStringSensor("test.str2"); + public static final AttributeSensor<String> STR3 = Sensors.newStringSensor("test.str3"); + public static final AttributeSensor<Integer> INT1 = Sensors.newIntegerSensor("test.int1"); + + private TestEntity entity; + + @BeforeMethod(alwaysRun=true) + @Override + public void setUp() throws Exception { + super.setUp(); + entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + } + + @Test + public void testBasicReducer(){ + entity.addEnricher(EnricherSpec.create(StringStringReducer.class).configure( + MutableMap.of( + Reducer.SOURCE_SENSORS, ImmutableList.of(STR1, STR2), + Reducer.PRODUCER, entity, + Reducer.TARGET_SENSOR, STR3, + Reducer.REDUCER_FUNCTION, new Concatenator()) + ) + ); + + EntityTestUtils.assertAttributeEquals(entity, STR3, null); + + entity.sensors().set(STR1, "foo"); + EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); + + entity.sensors().set(STR2, "bar"); + EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foobar"); + } + + @Test + public void testReducingBuilderWithConcatenator() { + entity.addEnricher(Enrichers.builder() + .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) + .from(entity) + .computing(new Concatenator()) + .publishing(STR3) + .build() + ); + + EntityTestUtils.assertAttributeEquals(entity, STR3, null); + + entity.sensors().set(STR1, "foo"); + EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); + + entity.sensors().set(STR2, "bar"); + EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foobar"); + } + + @Test + public void testReducingBuilderWithLengthCalculator() { + entity.addEnricher(Enrichers.builder() + .reducing(StringIntegerReducer.class, ImmutableList.of(STR1, STR2)) + .from(entity) + .computing(new LengthCalculator()) + .publishing(INT1) + .build() + ); + + EntityTestUtils.assertAttributeEquals(entity, INT1, null); + + entity.sensors().set(STR1, "foo"); + EntityTestUtils.assertAttributeEqualsContinually(entity, INT1, null); + + entity.sensors().set(STR2, "bar"); + EntityTestUtils.assertAttributeEqualsEventually(entity, INT1, 6); + } + + @Test + public void testReducingBuilderWithJoinerFunction() { + entity.addEnricher(Enrichers.builder() + .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) + .from(entity) + .computing("joiner", ImmutableMap.<String, Object>of("separator", "-")) + .publishing(STR3) + .build() + ); + + EntityTestUtils.assertAttributeEquals(entity, STR3, null); + + entity.sensors().set(STR1, "foo"); + EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); + + entity.sensors().set(STR2, "bar"); + EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foo-bar"); + } + + @Test + public void testReducingBuilderWithJoinerFunctionWithDefaultParameter() { + entity.addEnricher(Enrichers.builder() + .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) + .from(entity) + .computing("joiner") + .publishing(STR3) + .build() + ); + EntityTestUtils.assertAttributeEquals(entity, STR3, null); + + entity.sensors().set(STR1, "foo"); + EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); + + entity.sensors().set(STR2, "bar"); + EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foo, bar"); + } + + @Test + public void testReducingBuilderWithJoinerFunctionAndUnusedParameter() { + + entity.addEnricher(Enrichers.builder() + .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) + .from(entity) + .computing("joiner", ImmutableMap.<String, Object>of("non.existent.parameter", "-")) + .publishing(STR3) + .build() + ); + EntityTestUtils.assertAttributeEquals(entity, STR3, null); + + entity.sensors().set(STR1, "foo"); + EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); + + entity.sensors().set(STR2, "bar"); + EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "foo, bar"); + } + + @Test + public void testReducingBuilderWithFormatStringFunction() { + + entity.addEnricher(Enrichers.builder() + .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) + .from(entity) + .computing("formatString", ImmutableMap.<String, Object>of("format", "hello, %s and %s")) + .publishing(STR3) + .build() + ); + EntityTestUtils.assertAttributeEquals(entity, STR3, null); + + entity.sensors().set(STR1, "foo"); + EntityTestUtils.assertAttributeEqualsContinually(entity, STR3, null); + + entity.sensors().set(STR2, "bar"); + EntityTestUtils.assertAttributeEqualsEventually(entity, STR3, "hello, foo and bar"); + } + + @Test + public void testReducingBuilderWithNamedNonExistentFunction() { + try { + entity.addEnricher(Enrichers.builder() + .reducing(StringStringReducer.class, ImmutableList.of(STR1, STR2)) + .from(entity) + .computing("unknown function name", ImmutableMap.<String, Object>of("separator", "-")) + .publishing(STR3) + .build() + ); + Asserts.fail("Expected exception when adding reducing enricher with unknown named function"); + } catch (Exception e) { + Throwable t = Exceptions.getFirstThrowableOfType(e, IllegalStateException.class); + Assert.assertNotNull(t); + } + } + + private static class Concatenator implements Function<List<String>, String> { + @Nullable + @Override + public String apply(List<String> values) { + StringBuilder result = new StringBuilder(); + for (String value : values) { + if (value == null) { + return null; + } else { + result.append(value); + } + } + return result.toString(); + } + } + + public static class StringIntegerReducer extends Reducer<String, Integer> { + + public StringIntegerReducer() {} + + @Override + protected Function<List<String>, Integer> createReducerFunction( + String reducerName, Map<String, ?> parameters) { + throw new IllegalStateException("unknown function: " + reducerName); + } + + } + + private static class LengthCalculator implements Function<List<String>, Integer>{ + + @Override + public Integer apply(List<String> values) { + int acc = 0; + for (String value : values) { + if (value != null) { + acc += value.length(); + } + } + return acc; + } + + } +}
