brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [07/26] git commit: add support for suppressing duplicates in enrichers, defaulting false for most, but true for UpdatingMap; and in Enrichers.builder() use better superclasses to support tags, uniqueTags
Date Fri, 29 Aug 2014 23:01:07 GMT
add support for suppressing duplicates in enrichers, defaulting false for most, but true for
UpdatingMap; and in Enrichers.builder() use better superclasses to support tags, uniqueTags


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

Branch: refs/heads/master
Commit: 41deca4d9428867d9c1d54ec3e5334fe183cfea2
Parents: 3c714ed
Author: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Authored: Wed Aug 6 22:38:11 2014 -0400
Committer: Alex Heneveld <alex.heneveld@cloudsoftcorp.com>
Committed: Wed Aug 27 02:07:49 2014 -0400

----------------------------------------------------------------------
 .../main/java/brooklyn/enricher/Enrichers.java  | 111 +++++++++++++++----
 .../enricher/basic/AbstractEnricher.java        |  35 ++++++
 .../brooklyn/enricher/basic/Transformer.java    |   7 +-
 .../brooklyn/enricher/basic/UpdatingMap.java    |  13 ++-
 .../policy/basic/AbstractEntityAdjunct.java     |   2 +
 .../java/brooklyn/enricher/EnrichersTest.java   |  43 ++++---
 6 files changed, 163 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/41deca4d/core/src/main/java/brooklyn/enricher/Enrichers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/Enrichers.java b/core/src/main/java/brooklyn/enricher/Enrichers.java
index 0d3a0d5..23b1b83 100644
--- a/core/src/main/java/brooklyn/enricher/Enrichers.java
+++ b/core/src/main/java/brooklyn/enricher/Enrichers.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.enricher.basic.Aggregator;
 import brooklyn.enricher.basic.Combiner;
 import brooklyn.enricher.basic.Propagator;
@@ -39,12 +40,14 @@ import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
 import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -67,6 +70,48 @@ public class Enrichers {
         }
     }
     
+    public abstract static class AbstractEnricherBuilder<B extends AbstractEnricherBuilder<B>>
extends Builder<B> {
+        final Class<? extends Enricher> enricherType;
+        Boolean suppressDuplicates;
+        String uniqueTag;
+        Set<Object> tags = MutableSet.of();
+        
+        public AbstractEnricherBuilder(Class<? extends Enricher> enricherType) {
+            this.enricherType = enricherType;
+        }
+        
+        public B uniqueTag(String tag) {
+            uniqueTag = Preconditions.checkNotNull(tag);
+            return self();
+        }
+        public B addTag(Object tag) {
+            tags.add(Preconditions.checkNotNull(tag));
+            return self();
+        }
+        public B suppressDuplicates(Boolean suppressDuplicates) {
+            this.suppressDuplicates = suppressDuplicates;
+            return self();
+        }
+
+        protected abstract String getDefaultUniqueTag();
+        
+        protected EnricherSpec<?> build() {
+            EnricherSpec<? extends Enricher> spec = EnricherSpec.create(enricherType);
+            
+            String uniqueTag2 = uniqueTag;
+            if (uniqueTag!=null)
+                uniqueTag2 = getDefaultUniqueTag();
+            if (uniqueTag2!=null)
+                spec.uniqueTag(uniqueTag2);
+            
+            if (!tags.isEmpty()) spec.tags(tags);
+            if (suppressDuplicates!=null)
+                spec.configure(AbstractEnricher.SUPPRESS_DUPLICATES, suppressDuplicates);
+            
+            return spec;
+        }
+    }
+    
     protected abstract static class AbstractInitialBuilder<B extends AbstractInitialBuilder<B>>
extends Builder<B> {
         public PropagatorBuilder propagating(Map<? extends Sensor<?>, ? extends
Sensor<?>> vals) {
             return new PropagatorBuilder(vals);
@@ -117,7 +162,7 @@ public class Enrichers {
     }
 
 
-    protected abstract static class AbstractAggregatorBuilder<S, T, B extends AbstractAggregatorBuilder<S,
T, B>> extends Builder<B> {
+    protected abstract static class AbstractAggregatorBuilder<S, T, B extends AbstractAggregatorBuilder<S,
T, B>> extends AbstractEnricherBuilder<B> {
         protected final AttributeSensor<S> aggregating;
         protected AttributeSensor<T> publishing;
         protected Entity fromEntity;
@@ -132,6 +177,7 @@ public class Enrichers {
         protected Object valueToReportIfNoSensors;
         
         public AbstractAggregatorBuilder(AttributeSensor<S> aggregating) {
+            super(Aggregator.class);
             this.aggregating = aggregating;
         }
         @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -195,6 +241,11 @@ public class Enrichers {
             this.excludingBlank = true;
             return self();
         }
+        @Override
+        protected String getDefaultUniqueTag() {
+            if (publishing==null) return null;
+            return "aggregator:"+publishing.getName();
+        }
         public EnricherSpec<?> build() {
             Predicate<Object> valueFilter;
             if (Boolean.TRUE.equals(excludingBlank)) {
@@ -208,9 +259,7 @@ public class Enrichers {
                 valueFilter = null;
             }
             // FIXME excludingBlank; use valueFilter? exclude means ignored entirely or substituted
for defaultMemberValue?
-            return EnricherSpec.create(Aggregator.class)
-                    .uniqueTag("aggregator:"+publishing)
-                    .configure(MutableMap.builder()
+            return super.build().configure(MutableMap.builder()
                             .putIfNotNull(Aggregator.PRODUCER, fromEntity)
                             .put(Aggregator.TARGET_SENSOR, publishing)
                             .put(Aggregator.SOURCE_SENSOR, aggregating)
@@ -244,7 +293,7 @@ public class Enrichers {
         }
     }
     
-    protected abstract static class AbstractCombinerBuilder<S, T, B extends AbstractCombinerBuilder<S,
T, B>> extends Builder<B> {
+    protected abstract static class AbstractCombinerBuilder<S, T, B extends AbstractCombinerBuilder<S,
T, B>> extends AbstractEnricherBuilder<B> {
         protected final List<AttributeSensor<? extends S>> combining;
         protected AttributeSensor<T> publishing;
         protected Entity fromEntity;
@@ -260,6 +309,7 @@ public class Enrichers {
             this(ImmutableList.copyOf(vals));
         }
         public AbstractCombinerBuilder(Collection<AttributeSensor<? extends S>>
vals) {
+            super(Combiner.class);
             checkArgument(checkNotNull(vals).size() > 0, "combining-sensors must be non-empty");
             this.combining = ImmutableList.<AttributeSensor<? extends S>>copyOf(vals);
         }
@@ -306,10 +356,13 @@ public class Enrichers {
             this.excludingBlank = true;
             return self();
         }
+        @Override
+        protected String getDefaultUniqueTag() {
+            if (publishing==null) return null;
+            return "combiner:"+publishing.getName();
+        }
         public EnricherSpec<?> build() {
-            return EnricherSpec.create(Combiner.class)
-                    .uniqueTag("combiner:"+publishing)
-                    .configure(MutableMap.builder()
+            return super.build().configure(MutableMap.builder()
                             .putIfNotNull(Combiner.PRODUCER, fromEntity)
                             .put(Combiner.TARGET_SENSOR, publishing)
                             .put(Combiner.SOURCE_SENSORS, combining)
@@ -333,7 +386,7 @@ public class Enrichers {
         }
     }
 
-    protected abstract static class AbstractTransformerBuilder<S, T, B extends AbstractTransformerBuilder<S,
T, B>> extends Builder<B> {
+    protected abstract static class AbstractTransformerBuilder<S, T, B extends AbstractTransformerBuilder<S,
T, B>> extends AbstractEnricherBuilder<B> {
         protected final AttributeSensor<S> transforming;
         protected AttributeSensor<T> publishing;
         protected Entity fromEntity;
@@ -341,6 +394,7 @@ public class Enrichers {
         protected Function<? super SensorEvent<S>, ?> computingFromEvent;
 
         public AbstractTransformerBuilder(AttributeSensor<S> val) {
+            super(Transformer.class);
             this.transforming = checkNotNull(val);
         }
         @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -360,10 +414,13 @@ public class Enrichers {
             this.computingFromEvent = checkNotNull(val);
             return self();
         }
+        @Override
+        protected String getDefaultUniqueTag() {
+            if (publishing==null) return null;
+            return "transformer:"+publishing.getName();
+        }
         public EnricherSpec<?> build() {
-            return EnricherSpec.create(Transformer.class)
-                    .uniqueTag("transformer:"+publishing)
-                    .configure(MutableMap.builder()
+            return super.build().configure(MutableMap.builder()
                             .putIfNotNull(Transformer.PRODUCER, fromEntity)
                             .put(Transformer.TARGET_SENSOR, publishing)
                             .put(Transformer.SOURCE_SENSOR, transforming)
@@ -384,13 +441,14 @@ public class Enrichers {
         }
     }
 
-    protected abstract static class AbstractPropagatorBuilder<B extends AbstractPropagatorBuilder<B>>
extends Builder<B> {
+    protected abstract static class AbstractPropagatorBuilder<B extends AbstractPropagatorBuilder<B>>
extends AbstractEnricherBuilder<B> {
         protected final Map<? extends Sensor<?>, ? extends Sensor<?>> propagating;
         protected final Boolean propagatingAll;
         protected final Iterable<? extends Sensor<?>> propagatingAllBut;
         protected Entity fromEntity;
         
         public AbstractPropagatorBuilder(Map<? extends Sensor<?>, ? extends Sensor<?>>
vals) {
+            super(Propagator.class);
             checkArgument(checkNotNull(vals).size() > 0, "propagating-sensors must be
non-empty");
             this.propagating = vals;
             this.propagatingAll = null;
@@ -402,7 +460,8 @@ public class Enrichers {
         public AbstractPropagatorBuilder(Sensor<?>... vals) {
             this(newIdentityMap(ImmutableSet.copyOf(vals)));
         }
-        public AbstractPropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>>
butVals) {
+        AbstractPropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>>
butVals) {
+            super(Propagator.class);
             // Ugly constructor! Taking boolean to differentiate it from others; could use
a static builder
             // but feels like overkill having a builder for a builder, being called by a
builder!
             checkArgument(propagatingAll, "Not propagating all; use PropagatingAll(vals)");
@@ -414,7 +473,8 @@ public class Enrichers {
             this.fromEntity = checkNotNull(val);
             return self();
         }
-        public EnricherSpec<? extends Enricher> build() {
+        @Override
+        protected String getDefaultUniqueTag() {
             List<String> summary = MutableList.of();
             if (propagating!=null) {
                 for (Map.Entry<? extends Sensor<?>, ? extends Sensor<?>>
entry: propagating.entrySet()) {
@@ -432,9 +492,10 @@ public class Enrichers {
                 summary.add("ALL_BUT:"+Joiner.on(",").join(allBut));
             }
             
-            return EnricherSpec.create(Propagator.class)
-                    .uniqueTag("propagating["+fromEntity.getId()+":"+Joiner.on(",").join(summary)+"]")
-                    .configure(MutableMap.builder()
+            return "propagating["+fromEntity.getId()+":"+Joiner.on(",").join(summary)+"]";
+        }
+        public EnricherSpec<? extends Enricher> build() {
+            return super.build().configure(MutableMap.builder()
                             .putIfNotNull(Propagator.PRODUCER, fromEntity)
                             .putIfNotNull(Propagator.SENSOR_MAPPING, propagating)
                             .putIfNotNull(Propagator.PROPAGATING_ALL, propagatingAll)
@@ -454,7 +515,7 @@ public class Enrichers {
         }
     }
 
-    public abstract static class AbstractUpdatingMapBuilder<S, TKey, TVal, B extends AbstractUpdatingMapBuilder<S,
TKey, TVal, B>> extends Builder<B> {
+    public abstract static class AbstractUpdatingMapBuilder<S, TKey, TVal, B extends AbstractUpdatingMapBuilder<S,
TKey, TVal, B>> extends AbstractEnricherBuilder<B> {
         protected AttributeSensor<Map<TKey,TVal>> targetSensor;
         protected AttributeSensor<? extends S> fromSensor;
         protected TKey key;
@@ -462,6 +523,7 @@ public class Enrichers {
         protected Boolean removingIfResultIsNull;
         
         public AbstractUpdatingMapBuilder(AttributeSensor<Map<TKey,TVal>> target)
{
+            super(UpdatingMap.class);
             this.targetSensor = target;
         }
         @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -484,10 +546,13 @@ public class Enrichers {
             this.removingIfResultIsNull = val;
             return self();
         }
+        @Override
+        protected String getDefaultUniqueTag() {
+            if (targetSensor==null || fromSensor==null) return null;
+            return "updating:"+targetSensor.getName()+"<-"+fromSensor.getName();
+        }
         public EnricherSpec<?> build() {
-            return EnricherSpec.create(UpdatingMap.class)
-                    .uniqueTag("updating:"+targetSensor+"<-"+fromSensor)
-                    .configure(MutableMap.builder()
+            return super.build().configure(MutableMap.builder()
                             .put(UpdatingMap.TARGET_SENSOR, targetSensor)
                             .put(UpdatingMap.SOURCE_SENSOR, fromSensor)
                             .putIfNotNull(UpdatingMap.KEY_IN_TARGET_SENSOR, key)
@@ -528,7 +593,7 @@ public class Enrichers {
         public PropagatorBuilder(Sensor<?>... vals) {
             super(vals);
         }
-        public PropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>>
butVals) {
+        PropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>>
butVals) {
             super(propagatingAll, butVals);
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/41deca4d/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
index 9cba5b9..52a924a 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -18,15 +18,23 @@
  */
 package brooklyn.enricher.basic;
 
+import static com.google.common.base.Preconditions.checkState;
+
 import java.util.Map;
 
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.rebind.BasicEnricherRebindSupport;
 import brooklyn.entity.rebind.RebindSupport;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.Sensor;
 import brooklyn.mementos.EnricherMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherType;
 import brooklyn.policy.basic.AbstractEntityAdjunct;
 
+import com.google.common.base.Objects;
 import com.google.common.collect.Maps;
 
 /**
@@ -34,7 +42,11 @@ import com.google.common.collect.Maps;
 */
 public abstract class AbstractEnricher extends AbstractEntityAdjunct implements Enricher
{
 
+    public static final ConfigKey<Boolean> SUPPRESS_DUPLICATES = ConfigKeys.newBooleanConfigKey("enricher.suppressDuplicates",
+        "Whether duplicate values published by this enricher should be suppressed");
+
     private final EnricherDynamicType enricherType;
+    protected Boolean suppressDuplicates;
 
     public AbstractEnricher() {
         this(Maps.newLinkedHashMap());
@@ -61,8 +73,31 @@ public abstract class AbstractEnricher extends AbstractEntityAdjunct implements
     }
 
     @Override
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+        this.suppressDuplicates = getConfig(SUPPRESS_DUPLICATES);
+    }
+    
+    @Override
     protected void onChanged() {
         requestPersist();
     }
+
+    @Override
+    protected <T> void emit(Sensor<T> sensor, T val) {
+        checkState(entity != null, "entity must first be set");
+        
+        if (sensor instanceof AttributeSensor) {
+            if (Boolean.TRUE.equals(suppressDuplicates)) {
+                T oldValue = entity.getAttribute((AttributeSensor<T>)sensor);
+                if (Objects.equal(oldValue, val))
+                    return;
+            }
+            entity.setAttribute((AttributeSensor<T>)sensor, val);
+        } else { 
+            entity.emit(sensor, val);
+        }
+
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/41deca4d/core/src/main/java/brooklyn/enricher/basic/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Transformer.java b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
index 768e7c5..6877ec9 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Transformer.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
@@ -52,7 +52,7 @@ public class Transformer<T,U> extends AbstractEnricher implements
SensorEventLis
     public static ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new
TypeToken<Sensor<?>>() {}, "enricher.sourceSensor");
 
     public static ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new
TypeToken<Sensor<?>>() {}, "enricher.targetSensor");
-
+    
     protected Function<? super SensorEvent<T>, ? extends U> transformation;
     protected Entity producer;
     protected Sensor<T> sourceSensor;
@@ -65,6 +65,7 @@ public class Transformer<T,U> extends AbstractEnricher implements
SensorEventLis
     @Override
     public void setEntity(EntityLocal entity) {
         super.setEntity(entity);
+        
         final Function<? super T, ? extends U> transformationFromValue = (Function<?
super T, ? extends U>) getConfig(TRANSFORMATION_FROM_VALUE);
         final Function<? super SensorEvent<T>, ? extends U> transformationFromEvent
= (Function<? super SensorEvent<T>, ? extends U>) getConfig(TRANSFORMATION_FROM_EVENT);
         checkArgument(transformationFromEvent != null ^ transformationFromValue != null,
"must set exactly one of %s or %s", TRANSFORMATION_FROM_VALUE.getName(), TRANSFORMATION_FROM_EVENT.getName());
@@ -107,7 +108,9 @@ public class Transformer<T,U> extends AbstractEnricher implements
SensorEventLis
         if (v == Entities.UNCHANGED) {
             // nothing
         } else {
-            emit(targetSensor, TypeCoercions.coerce(v, targetSensor.getTypeToken()));
+            U newValue = TypeCoercions.coerce(v, targetSensor.getTypeToken());
+//            oldValue = entity.
+            emit(targetSensor, newValue);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/41deca4d/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java b/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java
index f85852c..60bbe4b 100644
--- a/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java
+++ b/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java
@@ -36,6 +36,7 @@ import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Function;
+import com.google.common.collect.Maps;
 import com.google.common.reflect.TypeToken;
 
 /**
@@ -47,7 +48,8 @@ import com.google.common.reflect.TypeToken;
  * with default behaviour being to remove an entry if <code>null</code> is returned
  * but this can be overriden by setting {@link #REMOVING_IF_RESULT_IS_NULL} false.
  * {@link Entities#REMOVE} and {@link Entities#UNCHANGED} are also respeced as return values
for the computation
- * (ignoring generics).  
+ * (ignoring generics).
+ * Unlike most other enrichers, this defaults to {@link AbstractEnricher#SUPPRESS_DUPLICATES}
being true
  *  
  * @author alex
  *
@@ -80,6 +82,15 @@ public class UpdatingMap<S,TKey,TVal> extends AbstractEnricher implements
Sensor
     protected Boolean removingIfResultIsNull;
 
     public UpdatingMap() {
+        this(Maps.newLinkedHashMap());
+    }
+
+    public UpdatingMap(Map<Object, Object> flags) {
+        super(flags);
+        if (suppressDuplicates==null) {
+            // this defaults to suppressing duplicates
+            suppressDuplicates = true;
+        }
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/41deca4d/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
index 4797b59..126968e 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -36,6 +36,7 @@ import brooklyn.basic.AbstractBrooklynObject;
 import brooklyn.basic.BrooklynObjectInternal;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigMap;
+import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
 import brooklyn.entity.basic.EntityInternal;
@@ -238,6 +239,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject
imple
         this.entity = entity;
     }
     
+    /** @deprecated since 0.7.0 only {@link AbstractEnricher} has emit convenience */
     protected <T> void emit(Sensor<T> sensor, T val) {
         checkState(entity != null, "entity must first be set");
         if (sensor instanceof AttributeSensor) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/41deca4d/core/src/test/java/brooklyn/enricher/EnrichersTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/enricher/EnrichersTest.java b/core/src/test/java/brooklyn/enricher/EnrichersTest.java
index ab3f199..4257c36 100644
--- a/core/src/test/java/brooklyn/enricher/EnrichersTest.java
+++ b/core/src/test/java/brooklyn/enricher/EnrichersTest.java
@@ -214,28 +214,27 @@ public class EnrichersTest extends BrooklynAppUnitTestSupport {
         Asserts.eventually(Suppliers.ofInstance(record.events), CollectionFunctionals.sizeEquals(5));
     }
 
-    // TODO if we had something like suppressDuplicates(true) :
-//    public void testTransformingSuppressDuplicates() {
-//        RecordingSensorEventListener record = new RecordingSensorEventListener();
-//        app.getManagementContext().getSubscriptionManager().subscribe(entity, STR2, record);
-//        
-//        entity.addEnricher(Enrichers.builder()
-//                .transforming(STR1)
-//                .publishing(STR2)
-//                .computing(Functions.<String>identity())
-//                .suppressDuplicates(true)
-//                .build());
-//
-//        entity.setAttribute(STR1, "myval");
-//        Asserts.eventually(Suppliers.ofInstance(record.events), CollectionFunctionals.sizeEquals(1));
-//        EntityTestUtils.assertAttributeEquals(entity, STR2, "myval");
-//        
-//        entity.setAttribute(STR1, "myval2");
-//        entity.setAttribute(STR1, "myval2");
-//        entity.setAttribute(STR1, "myval3");
-//        EntityTestUtils.assertAttributeEqualsContinually(entity, STR2, "myval3");
-//        Asserts.assertThat(record.events, CollectionFunctionals.sizeEquals(3));
-//    }
+    public void testTransformingSuppressDuplicates() {
+        RecordingSensorEventListener record = new RecordingSensorEventListener();
+        app.getManagementContext().getSubscriptionManager().subscribe(entity, STR2, record);
+        
+        entity.addEnricher(Enrichers.builder()
+                .transforming(STR1)
+                .publishing(STR2)
+                .computing(Functions.<String>identity())
+                .suppressDuplicates(true)
+                .build());
+
+        entity.setAttribute(STR1, "myval");
+        Asserts.eventually(Suppliers.ofInstance(record.events), CollectionFunctionals.sizeEquals(1));
+        EntityTestUtils.assertAttributeEquals(entity, STR2, "myval");
+        
+        entity.setAttribute(STR1, "myval2");
+        entity.setAttribute(STR1, "myval2");
+        entity.setAttribute(STR1, "myval3");
+        EntityTestUtils.assertAttributeEqualsContinually(entity, STR2, "myval3");
+        Asserts.assertThat(record.events, CollectionFunctionals.sizeEquals(3));
+    }
 
     @Test
     public void testPropagating() {


Mime
View raw message