You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/08/30 01:01:05 UTC

[05/26] git commit: refactor Enrichers.builder() types to give correct generics for published sensor

refactor Enrichers.builder() types to give correct generics for published sensor


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

Branch: refs/heads/master
Commit: 3c714ed12259c3909f0244f83f504e6a62be7bdb
Parents: 141751b
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Aug 6 22:09:15 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Aug 27 02:07:48 2014 -0400

----------------------------------------------------------------------
 .../main/java/brooklyn/enricher/Enrichers.java  | 132 ++++++++++---------
 .../java/brooklyn/enricher/EnrichersTest.java   |  55 +++++++-
 2 files changed, 115 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3c714ed1/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 6ddc780..0d3a0d5 100644
--- a/core/src/main/java/brooklyn/enricher/Enrichers.java
+++ b/core/src/main/java/brooklyn/enricher/Enrichers.java
@@ -56,8 +56,8 @@ public class Enrichers {
 
     private Enrichers() {}
     
-    public static InitialBuilder<?> builder() {
-        return new ConcreteInitialBuilder();
+    public static InitialBuilder builder() {
+        return new InitialBuilder();
     }
 
     public abstract static class Builder<B extends Builder<B>> {
@@ -67,36 +67,46 @@ public class Enrichers {
         }
     }
     
-    public abstract static class InitialBuilder<B extends InitialBuilder<B>> extends Builder<B> {
-        public PropagatorBuilder<?> propagating(Map<? extends Sensor<?>, ? extends Sensor<?>> vals) {
-            return new ConcretePropagatorBuilder(vals);
+    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);
         }
-        public PropagatorBuilder<?> propagating(Iterable<? extends Sensor<?>> vals) {
-            return new ConcretePropagatorBuilder(vals);
+        public PropagatorBuilder propagating(Iterable<? extends Sensor<?>> vals) {
+            return new PropagatorBuilder(vals);
         }
-        public PropagatorBuilder<?> propagating(Sensor<?>... vals) {
-            return new ConcretePropagatorBuilder(vals);
+        public PropagatorBuilder propagating(Sensor<?>... vals) {
+            return new PropagatorBuilder(vals);
         }
-        public PropagatorBuilder<?> propagatingAll() {
-            return new ConcretePropagatorBuilder(true, null);
+        public PropagatorBuilder propagatingAll() {
+            return new PropagatorBuilder(true, null);
         }
-        public PropagatorBuilder<?> propagatingAllBut(Sensor<?>... vals) {
-            return new ConcretePropagatorBuilder(true, ImmutableSet.copyOf(vals));
+        public PropagatorBuilder propagatingAllBut(Sensor<?>... vals) {
+            return new PropagatorBuilder(true, ImmutableSet.copyOf(vals));
         }
-        public PropagatorBuilder<?> propagatingAllBut(Iterable<? extends Sensor<?>> vals) {
-            return new ConcretePropagatorBuilder(true, vals);
+        public PropagatorBuilder propagatingAllBut(Iterable<? extends Sensor<?>> vals) {
+            return new PropagatorBuilder(true, vals);
         }
-        public <S> TransformerBuilder<S, Object, ?> transforming(AttributeSensor<S> val) {
-            return new ConcreteTransformerBuilder<S, Object>(val);
-        }
-        public <S> CombinerBuilder<S, Object, ?> combining(AttributeSensor<? extends S>... vals) {
-            return new ConcreteCombinerBuilder<S, Object>(vals);
-        }
-        public <S> CombinerBuilder<S, Object, ?> combining(Collection<AttributeSensor<? extends S>> vals) {
-            return new ConcreteCombinerBuilder<S, Object>(vals);
-        }
-        public <S> AggregatorBuilder<S, Object, ?> aggregating(AttributeSensor<S> val) {
-            return new ConcreteAggregatorBuilder<S,Object>(val);
+        
+        /** builds an enricher which transforms a given sensor:
+         * <li> applying a (required) function ({@link TransformerBuilder#computing(Function)}, or {@link TransformerBuilder#computingAverage()}/{@link TransformerBuilder#computingSum()}, mandatory);
+         * <li> and publishing it on the entity where the enricher is attached;
+         * <li> optionally taking the sensor from a different source entity ({@link TransformerBuilder#from(Entity)});
+         * <li> and optionally publishing it as a different sensor ({@link TransformerBuilder#publishing(AttributeSensor)});
+         * <p> (You must supply at least one of the optional values, of course, otherwise the enricher may loop endlessly!) */
+        public <S> TransformerBuilder<S, Object> transforming(AttributeSensor<S> val) {
+            return new TransformerBuilder<S, Object>(val);
+        }
+        /** as {@link #transforming(AttributeSensor)} but accepting multiple sensors, with the function acting on the set of values */
+        public <S> CombinerBuilder<S, Object> combining(Collection<AttributeSensor<? extends S>> vals) {
+            return new CombinerBuilder<S, Object>(vals);
+        }
+        /** as {@link #combining(Collection)} */
+        public <S> CombinerBuilder<S, Object> combining(AttributeSensor<? extends S>... vals) {
+            return new CombinerBuilder<S, Object>(vals);
+        }
+        /** as {@link #combining(Collection)} but the collection of values comes from the given sensor on multiple entities */
+        public <S> AggregatorBuilder<S, Object> aggregating(AttributeSensor<S> val) {
+            return new AggregatorBuilder<S,Object>(val);
         }
         /** creates an {@link UpdatingMap} enricher: 
          * {@link UpdatingMapBuilder#from(AttributeSensor)} and {@link UpdatingMapBuilder#computing(Function)} are required
@@ -107,7 +117,7 @@ public class Enrichers {
     }
 
 
-    public abstract static class AggregatorBuilder<S, T, B extends AggregatorBuilder<S, T, B>> extends Builder<B> {
+    protected abstract static class AbstractAggregatorBuilder<S, T, B extends AbstractAggregatorBuilder<S, T, B>> extends Builder<B> {
         protected final AttributeSensor<S> aggregating;
         protected AttributeSensor<T> publishing;
         protected Entity fromEntity;
@@ -121,15 +131,13 @@ public class Enrichers {
         protected Object defaultValueForUnreportedSensors;
         protected Object valueToReportIfNoSensors;
         
-        public AggregatorBuilder(AttributeSensor<S> aggregating) {
+        public AbstractAggregatorBuilder(AttributeSensor<S> aggregating) {
             this.aggregating = aggregating;
         }
-        // TODO change the signature of this to have correct type info as done for UpdatingMapBuilder.from(Sensor)
-        // (including change *Builder to Abstract*Builder and Concrete*Builder to *Builder, for all other enricher types)
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        public B publishing(AttributeSensor<? extends T> val) {
+        public <T2 extends T> AggregatorBuilder<S,T2> publishing(AttributeSensor<? extends T2> val) {
             this.publishing = (AttributeSensor) checkNotNull(val);
-            return self();
+            return (AggregatorBuilder) self();
         }
         public B from(Entity val) {
             this.fromEntity = checkNotNull(val);
@@ -236,7 +244,7 @@ public class Enrichers {
         }
     }
     
-    public abstract static class CombinerBuilder<S, T, B extends CombinerBuilder<S, T, B>> extends Builder<B> {
+    protected abstract static class AbstractCombinerBuilder<S, T, B extends AbstractCombinerBuilder<S, T, B>> extends Builder<B> {
         protected final List<AttributeSensor<? extends S>> combining;
         protected AttributeSensor<T> publishing;
         protected Entity fromEntity;
@@ -248,17 +256,17 @@ public class Enrichers {
         // For summing/averaging
         protected Object defaultValueForUnreportedSensors;
         
-        public CombinerBuilder(AttributeSensor<? extends S>... vals) {
+        public AbstractCombinerBuilder(AttributeSensor<? extends S>... vals) {
             this(ImmutableList.copyOf(vals));
         }
-        public CombinerBuilder(Collection<AttributeSensor<? extends S>> vals) {
+        public AbstractCombinerBuilder(Collection<AttributeSensor<? extends S>> vals) {
             checkArgument(checkNotNull(vals).size() > 0, "combining-sensors must be non-empty");
             this.combining = ImmutableList.<AttributeSensor<? extends S>>copyOf(vals);
         }
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        public B publishing(AttributeSensor<? extends T> val) {
+        public <T2 extends T> CombinerBuilder<S,T2> publishing(AttributeSensor<? extends T2> val) {
             this.publishing = (AttributeSensor) checkNotNull(val);
-            return self();
+            return (CombinerBuilder) this;
         }
         public B from(Entity val) {
             this.fromEntity = checkNotNull(val);
@@ -325,26 +333,20 @@ public class Enrichers {
         }
     }
 
-    /** builds an enricher which transforms a given sensor:
-     * <li> applying a function ({@link #computing(Function)}, or {@link #computingAverage()}/{@link #computingSum()}, mandatory);
-     * <li> and publishing it on the entity where the enricher is attached;
-     * <li> optionally taking the sensor from a different source entity ({@link #from(Entity)});
-     * <li> and optionally publishing it as a different sensor ({@link #publishing(AttributeSensor)});
-     * <p> (You should supply at least one of the optional values, of course, otherwise the enricher may loop endlessly!) */
-    public abstract static class TransformerBuilder<S, T, B extends TransformerBuilder<S, T, B>> extends Builder<B> {
+    protected abstract static class AbstractTransformerBuilder<S, T, B extends AbstractTransformerBuilder<S, T, B>> extends Builder<B> {
         protected final AttributeSensor<S> transforming;
         protected AttributeSensor<T> publishing;
         protected Entity fromEntity;
         protected Function<? super S, ?> computing;
         protected Function<? super SensorEvent<S>, ?> computingFromEvent;
 
-        public TransformerBuilder(AttributeSensor<S> val) {
+        public AbstractTransformerBuilder(AttributeSensor<S> val) {
             this.transforming = checkNotNull(val);
         }
         @SuppressWarnings({ "unchecked", "rawtypes" })
-        public B publishing(AttributeSensor<? extends T> val) {
+        public <T2 extends T> TransformerBuilder<S,T2> publishing(AttributeSensor<? extends T2> val) {
             this.publishing = (AttributeSensor) checkNotNull(val);
-            return self();
+            return (TransformerBuilder) this;
         }
         public B from(Entity val) {
             this.fromEntity = checkNotNull(val);
@@ -382,25 +384,25 @@ public class Enrichers {
         }
     }
 
-    public abstract static class PropagatorBuilder<B extends PropagatorBuilder<B>> extends Builder<B> {
+    protected abstract static class AbstractPropagatorBuilder<B extends AbstractPropagatorBuilder<B>> extends Builder<B> {
         protected final Map<? extends Sensor<?>, ? extends Sensor<?>> propagating;
         protected final Boolean propagatingAll;
         protected final Iterable<? extends Sensor<?>> propagatingAllBut;
         protected Entity fromEntity;
         
-        public PropagatorBuilder(Map<? extends Sensor<?>, ? extends Sensor<?>> vals) {
+        public AbstractPropagatorBuilder(Map<? extends Sensor<?>, ? extends Sensor<?>> vals) {
             checkArgument(checkNotNull(vals).size() > 0, "propagating-sensors must be non-empty");
             this.propagating = vals;
             this.propagatingAll = null;
             this.propagatingAllBut = null;
         }
-        public PropagatorBuilder(Iterable<? extends Sensor<?>> vals) {
+        public AbstractPropagatorBuilder(Iterable<? extends Sensor<?>> vals) {
             this(newIdentityMap(ImmutableSet.copyOf(vals)));
         }
-        public PropagatorBuilder(Sensor<?>... vals) {
+        public AbstractPropagatorBuilder(Sensor<?>... vals) {
             this(newIdentityMap(ImmutableSet.copyOf(vals)));
         }
-        public PropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>> butVals) {
+        public AbstractPropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>> butVals) {
             // 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)");
@@ -507,41 +509,41 @@ public class Enrichers {
         }
     }
 
-    private static class ConcreteInitialBuilder extends InitialBuilder<ConcreteInitialBuilder> {
+    public static class InitialBuilder extends AbstractInitialBuilder<InitialBuilder> {
     }
 
-    private static class ConcreteAggregatorBuilder<S, T> extends AggregatorBuilder<S, T, ConcreteAggregatorBuilder<S, T>> {
-        public ConcreteAggregatorBuilder(AttributeSensor<S> aggregating) {
+    public static class AggregatorBuilder<S, T> extends AbstractAggregatorBuilder<S, T, AggregatorBuilder<S, T>> {
+        public AggregatorBuilder(AttributeSensor<S> aggregating) {
             super(aggregating);
         }
     }
 
-    private static class ConcretePropagatorBuilder extends PropagatorBuilder<ConcretePropagatorBuilder> {
-        public ConcretePropagatorBuilder(Map<? extends Sensor<?>, ? extends Sensor<?>> vals) {
+    public static class PropagatorBuilder extends AbstractPropagatorBuilder<PropagatorBuilder> {
+        public PropagatorBuilder(Map<? extends Sensor<?>, ? extends Sensor<?>> vals) {
             super(vals);
         }
-        public ConcretePropagatorBuilder(Iterable<? extends Sensor<?>> vals) {
+        public PropagatorBuilder(Iterable<? extends Sensor<?>> vals) {
             super(vals);
         }
-        public ConcretePropagatorBuilder(Sensor<?>... vals) {
+        public PropagatorBuilder(Sensor<?>... vals) {
             super(vals);
         }
-        public ConcretePropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>> butVals) {
+        public PropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>> butVals) {
             super(propagatingAll, butVals);
         }
     }
 
-    private static class ConcreteCombinerBuilder<S, T> extends CombinerBuilder<S, T, ConcreteCombinerBuilder<S, T>> {
-        public ConcreteCombinerBuilder(AttributeSensor<? extends S>... vals) {
+    public static class CombinerBuilder<S, T> extends AbstractCombinerBuilder<S, T, CombinerBuilder<S, T>> {
+        public CombinerBuilder(AttributeSensor<? extends S>... vals) {
             super(vals);
         }
-        public ConcreteCombinerBuilder(Collection<AttributeSensor<? extends S>> vals) {
+        public CombinerBuilder(Collection<AttributeSensor<? extends S>> vals) {
             super(vals);
         }
     }
 
-    private static class ConcreteTransformerBuilder<S, T> extends TransformerBuilder<S, T, ConcreteTransformerBuilder<S, T>> {
-        public ConcreteTransformerBuilder(AttributeSensor<S> val) {
+    public static class TransformerBuilder<S, T> extends AbstractTransformerBuilder<S, T, TransformerBuilder<S, T>> {
+        public TransformerBuilder(AttributeSensor<S> val) {
             super(val);
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3c714ed1/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 8bfd2bb..ab3f199 100644
--- a/core/src/test/java/brooklyn/enricher/EnrichersTest.java
+++ b/core/src/test/java/brooklyn/enricher/EnrichersTest.java
@@ -28,12 +28,15 @@ import org.testng.annotations.Test;
 import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.entity.basic.BasicGroup;
 import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntitySubscriptionTest.RecordingSensorEventListener;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.event.basic.Sensors;
+import brooklyn.test.Asserts;
 import brooklyn.test.EntityTestUtils;
 import brooklyn.test.entity.TestEntity;
+import brooklyn.util.collections.CollectionFunctionals;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.guava.Functionals;
@@ -41,6 +44,7 @@ import brooklyn.util.text.StringFunctions;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
+import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -107,7 +111,7 @@ public class EnrichersTest extends BrooklynAppUnitTestSupport {
     public void testCombiningRespectsUnchanged() {
         entity.addEnricher(Enrichers.builder()
                 .combining(NUM1, NUM2)
-                .publishing(NUM3)
+                .<Object>publishing(NUM3)
                 .computing(new Function<Iterable<Integer>, Object>() {
                         @Override public Object apply(Iterable<Integer> input) {
                             if (input != null && Iterables.contains(input, 123)) {
@@ -156,7 +160,7 @@ public class EnrichersTest extends BrooklynAppUnitTestSupport {
         entity.addEnricher(Enrichers.builder()
                 .transforming(NUM1)
                 .publishing(LONG1)
-                .computing(Functions.constant(Integer.valueOf(1)))
+                .computing(Functions.constant(Long.valueOf(1)))
                 .build());
         
         entity.setAttribute(NUM1, 123);
@@ -179,23 +183,60 @@ public class EnrichersTest extends BrooklynAppUnitTestSupport {
     }
 
     @Test(groups="Integration") // because takes a second
-    public void testTransformingRespectsUnchanged() {
+    public void testTransformingRespectsUnchangedButWillRepublish() {
+        RecordingSensorEventListener record = new RecordingSensorEventListener();
+        app.getManagementContext().getSubscriptionManager().subscribe(entity, STR2, record);
+        
         entity.addEnricher(Enrichers.builder()
                 .transforming(STR1)
-                .publishing(STR2)
+                .<Object>publishing(STR2)
                 .computing(new Function<String, Object>() {
                         @Override public Object apply(String input) {
                             return ("ignoredval".equals(input)) ? Entities.UNCHANGED : input;
                         }})
                 .build());
+        Asserts.assertThat(record.events, CollectionFunctionals.sizeEquals(0));
         
         entity.setAttribute(STR1, "myval");
-        EntityTestUtils.assertAttributeEqualsEventually(entity, STR2, "myval");
+        Asserts.eventually(Suppliers.ofInstance(record.events), CollectionFunctionals.sizeEquals(1));
+        EntityTestUtils.assertAttributeEquals(entity, STR2, "myval");
         
         entity.setAttribute(STR1, "ignoredval");
         EntityTestUtils.assertAttributeEqualsContinually(entity, STR2, "myval");
+        
+        entity.setAttribute(STR1, "myval2");
+        Asserts.eventually(Suppliers.ofInstance(record.events), CollectionFunctionals.sizeEquals(2));
+        EntityTestUtils.assertAttributeEquals(entity, STR2, "myval2");
+        
+        entity.setAttribute(STR1, "myval2");
+        entity.setAttribute(STR1, "myval2");
+        entity.setAttribute(STR1, "myval3");
+        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));
+//    }
+
     @Test
     public void testPropagating() {
         entity.addEnricher(Enrichers.builder()
@@ -321,7 +362,7 @@ public class EnrichersTest extends BrooklynAppUnitTestSupport {
                 .aggregating(NUM1)
                 .publishing(LONG1)
                 .fromMembers()
-                .computing(Functions.constant(Integer.valueOf(1)))
+                .computing(Functions.constant(Long.valueOf(1)))
                 .build());
         
         entity.setAttribute(NUM1, 123);
@@ -333,7 +374,7 @@ public class EnrichersTest extends BrooklynAppUnitTestSupport {
         group.addMember(entity);
         group.addEnricher(Enrichers.builder()
                 .aggregating(NUM1)
-                .publishing(LONG1)
+                .<Object>publishing(LONG1)
                 .fromMembers()
                 .computing(new Function<Iterable<Integer>, Object>() {
                         @Override public Object apply(Iterable<Integer> input) {