http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java 
b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java
deleted file mode 100644
index 823b8b7..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.enricher;
-
-import static com.google.common.base.Preconditions.checkState;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-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.sensor.BasicSensorEvent;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-import com.google.common.reflect.TypeToken;
-
-@SuppressWarnings("serial")
-//@Catalog(name="Combiner", description="Combines attributes; see 
Enrichers.builder().combining(...)")
-public class Combiner<T,U> extends AbstractEnricher implements 
SensorEventListener<T> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(Combiner.class);
-
-    public static ConfigKey<Function<?, ?>> TRANSFORMATION = 
ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, 
"enricher.transformation");
-
-    public static ConfigKey<Entity> PRODUCER = 
ConfigKeys.newConfigKey(Entity.class, "enricher.producer");
-
-    public static ConfigKey<Set<Sensor<?>>> SOURCE_SENSORS = 
ConfigKeys.newConfigKey(new TypeToken<Set<Sensor<?>>>() {}, 
"enricher.sourceSensors");
-
-    public static ConfigKey<Sensor<?>> TARGET_SENSOR = 
ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor");
-
-    public static final ConfigKey<Predicate<?>> VALUE_FILTER = 
ConfigKeys.newConfigKey(new TypeToken<Predicate<?>>() {}, 
"enricher.aggregating.valueFilter");
-
-    protected Function<? super Collection<T>, ? extends U> transformation;
-    protected Entity producer;
-    protected Set<Sensor<T>> sourceSensors;
-    protected Sensor<U> targetSensor;
-    protected Predicate<? super T> valueFilter;
-
-    /**
-     * Users of values should either on it synchronize when iterating over its 
entries or use
-     * copyOfValues to obtain an immutable copy of the map.
-     */
-    // We use a synchronizedMap over a ConcurrentHashMap for entities that 
store null values.
-    protected final Map<Sensor<T>, T> values = Collections.synchronizedMap(new 
LinkedHashMap<Sensor<T>, T>());
-
-    public Combiner() {
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        this.transformation = (Function<? super Collection<T>, ? extends U>) 
getRequiredConfig(TRANSFORMATION);
-        this.producer = getConfig(PRODUCER) == null ? entity: 
getConfig(PRODUCER);
-        this.sourceSensors = (Set) getRequiredConfig(SOURCE_SENSORS);
-        this.targetSensor = (Sensor<U>) getRequiredConfig(TARGET_SENSOR);
-        this.valueFilter = (Predicate<? super T>) (getConfig(VALUE_FILTER) == 
null ? Predicates.alwaysTrue() : getConfig(VALUE_FILTER));
-        
-        checkState(sourceSensors.size() > 0, "must specify at least one 
sourceSensor");
-
-        for (Sensor<T> sourceSensor : sourceSensors) {
-            subscribe(producer, sourceSensor, this);
-        }
-        
-        for (Sensor<T> sourceSensor : sourceSensors) {
-            if (sourceSensor instanceof AttributeSensor) {
-                Object value = 
producer.getAttribute((AttributeSensor<?>)sourceSensor);
-                // TODO Aled didn't you write a convenience to 
"subscribeAndRunIfSet" ? (-Alex)
-                //      Unfortunately not yet!
-                if (value != null) {
-                    onEvent(new BasicSensorEvent(sourceSensor, producer, 
value, -1));
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onEvent(SensorEvent<T> event) {
-        synchronized (values) {
-            values.put(event.getSensor(), event.getValue());
-        }
-        onUpdated();
-    }
-
-    /**
-     * Called whenever the values for the set of producers changes (e.g. on an 
event, or on a member added/removed).
-     */
-    protected void onUpdated() {
-        try {
-            emit(targetSensor, compute());
-        } catch (Throwable t) {
-            LOG.warn("Error calculating and setting combination for enricher 
"+this, t);
-            throw Exceptions.propagate(t);
-        }
-    }
-    
-    protected Object compute() {
-        synchronized (values) {
-            // TODO Could avoid copying when filter not needed
-            List<T> vs = MutableList.copyOf(Iterables.filter(values.values(), 
valueFilter));
-            return transformation.apply(vs);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricher.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricher.java
 
b/core/src/main/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricher.java
deleted file mode 100644
index c11b83a..0000000
--- 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricher.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.enricher;
-
-import groovy.lang.Closure;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.SensorEventListener;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Function;
-import com.google.common.base.Throwables;
-import com.google.common.reflect.TypeToken;
-
-/**
- * Subscribes to events from producers with a sensor of type T, aggregates 
them with the 
- * provided closure and emits the result on the target sensor V.
- * @param <T>
- * 
- * @deprecated since 0.7.0; use {@link Enrichers#builder()}
- */
-public class CustomAggregatingEnricher<S,T> extends 
AbstractAggregatingEnricher<S,T> implements SensorEventListener<S> {
-    
-    private static final Logger LOG = 
LoggerFactory.getLogger(CustomAggregatingEnricher.class);
-    
-    protected final Function<Collection<S>, T> aggregator;
-    
-    /**
-     * The valid keys for the flags are:
-     * - producers: a collection of entities to be aggregated
-     * - allMembers: indicates that should track members of the entity that 
the aggregator is associated with,
-     *               to aggregate across all those members.
-     * - filter:     a Predicate or Closure, indicating which entities to 
include
-     * 
-     * @param flags
-     * @param source
-     * @param target
-     * @param aggregator   Aggregates a collection of values, to return a 
single value for the target sensor
-     * @param defaultIniitalValueForUnreportedSensors Default value to 
populate the collection given to aggregator, 
-     * where sensors are null or not present initially, defaults to null (note 
however that subsequent null reports will put an explicit null)
-     */
-    public CustomAggregatingEnricher(Map<String,?> flags, AttributeSensor<? 
extends S> source, AttributeSensor<T> target,
-            Function<Collection<S>, T> aggregator, S 
defaultIniitalValueForUnreportedSensors) {
-        super(flags, source, target, defaultIniitalValueForUnreportedSensors);
-        this.aggregator = aggregator;
-    }
-    
-    public CustomAggregatingEnricher(Map<String,?> flags, AttributeSensor<? 
extends S> source, AttributeSensor<T> target,
-            Function<Collection<S>, T> aggregator) {
-        this(flags, source, target, aggregator, null);
-    }
-    
-    public CustomAggregatingEnricher(AttributeSensor<? extends S> source, 
AttributeSensor<T> target,
-            Function<Collection<S>, T> aggregator, S defaultValue) {
-        this(Collections.<String,Object>emptyMap(), source, target, 
aggregator, defaultValue);
-    }
-    
-    public CustomAggregatingEnricher(AttributeSensor<? extends S> source, 
AttributeSensor<T> target,
-            Function<Collection<S>, T> aggregator) {
-        this(Collections.<String,Object>emptyMap(), source, target, 
aggregator, null);
-    }
-
-    /**
-     * @param flags
-     * @param source
-     * @param target
-     * @param aggregator   Should take a collection of values and return a 
single, aggregate value
-     * @param defaultValueForUnreportedSensors
-     * 
-     * @see #CustomAggregatingEnricher(Map, AttributeSensor, AttributeSensor, 
Function, Object)
-     */
-    @SuppressWarnings("unchecked")
-    public CustomAggregatingEnricher(Map<String,?> flags, AttributeSensor<? 
extends S> source, AttributeSensor<T> target,
-            Closure<?> aggregator, S defaultValueForUnreportedSensors) {
-        this(flags, source, target, GroovyJavaMethods.<Collection<S>, 
T>functionFromClosure((Closure<T>)aggregator), 
defaultValueForUnreportedSensors);
-    }
-
-    public CustomAggregatingEnricher(Map<String,?> flags, AttributeSensor<? 
extends S> source, AttributeSensor<T> target, Closure<?> aggregator) {
-        this(flags, source, target, aggregator, null);
-    }
-
-    public CustomAggregatingEnricher(AttributeSensor<S> source, 
AttributeSensor<T> target, Closure<?> aggregator, S 
defaultValueForUnreportedSensors) {
-        this(Collections.<String,Object>emptyMap(), source, target, 
aggregator, defaultValueForUnreportedSensors);
-    }
-
-    public CustomAggregatingEnricher(AttributeSensor<S> source, 
AttributeSensor<T> target, Closure<?> aggregator) {
-        this(Collections.<String,Object>emptyMap(), source, target, 
aggregator, null);
-    }
-
-    @Override
-    public void onUpdated() {
-        try {
-            entity.setAttribute(target, getAggregate());
-        } catch (Throwable t) {
-            LOG.warn("Error calculating and setting aggregate for enricher 
"+this, t);
-            throw Throwables.propagate(t);
-        }
-    }
-    
-    public T getAggregate() {
-        synchronized (values) {
-            return (T) aggregator.apply(values.values());
-        }
-    }
-
-    /**
-     * Instead, consider calling:
-     * <pre>
-     * {@code
-     * Enrichers.Builder builder = Enrichers.builder()
-     *         .aggregating(source)
-     *         .publishing(target)
-     *         .computing(GroovyJavaMethods.<Collection<S>, 
T>functionFromClosure((Closure<T>)aggregator))
-     *         
.defaultValueForUnreportedSensors(defaultValueForUnreportedSensors);
-     * 
-     * if (Boolean.TRUE.equals(allMembers)) builder.fromMembers();
-     * if (filter != null) builder.entityFilter(filter);
-     * if (hardCodedProducers != null) 
builder.fromHardcodedProducers(hardCodedProducers);
-     * 
-     * addEnricher(builder.build());
-     * }
-     * </pre>
-     *
-     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
-     */
-    public static <S,T> CustomAggregatingEnricher<S,T> newEnricher(
-            Map<String,?> flags, AttributeSensor<S> source, AttributeSensor<T> 
target, Closure<?> aggregator, S defaultVal) {
-        return new CustomAggregatingEnricher<S,T>(flags, source, target, 
aggregator, defaultVal);
-    }
-    public static <S,T> CustomAggregatingEnricher<S,T> newEnricher(
-            Map<String,?> flags, AttributeSensor<S> source, AttributeSensor<T> 
target, Closure<?> aggregator) {
-        return newEnricher(flags, source, target, aggregator, null);
-    }
-    public static <S,T> CustomAggregatingEnricher<S,T> newEnricher(
-            AttributeSensor<S> source, AttributeSensor<T> target, Closure<?> 
aggregator, S defaultVal) {
-        return newEnricher(Collections.<String,Object>emptyMap(), source, 
target, aggregator, defaultVal);
-    }
-    public static <S,T> CustomAggregatingEnricher<S,T> newEnricher(
-            AttributeSensor<S> source, AttributeSensor<T> target, Closure<?> 
aggregator) {
-        return newEnricher(Collections.<String,Object>emptyMap(), source, 
target, aggregator, null);
-    }
-    
-    /**
-     * Instead, consider calling:
-     * <pre>
-     * {@code
-     * Enrichers.Builder builder = Enrichers.builder()
-     *         .aggregating(source)
-     *         .publishing(target)
-     *         .computing(aggregator)
-     *         .defaultValueForUnreportedSensors(defaultVal);
-     * 
-     * if (Boolean.TRUE.equals(allMembers)) builder.fromMembers();
-     * if (filter != null) builder.entityFilter(filter);
-     * if (hardCodedProducers != null) 
builder.fromHardcodedProducers(hardCodedProducers);
-     * 
-     * addEnricher(builder.build());
-     * }
-     * </pre>
-     *
-     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
-     */
-    public static <S,T> CustomAggregatingEnricher<S,T> newEnricher(
-            Map<String,?> flags, AttributeSensor<S> source, AttributeSensor<T> 
target, Function<Collection<S>, T> aggregator, S defaultVal) {
-        return new CustomAggregatingEnricher<S,T>(flags, source, target, 
aggregator, defaultVal);
-    }
-    public static <S,T> CustomAggregatingEnricher<S,T> newEnricher(
-            Map<String,?> flags, AttributeSensor<S> source, AttributeSensor<T> 
target, Function<Collection<S>, T> aggregator) {
-        return newEnricher(flags, source, target, aggregator, null);
-    }
-    public static <S,T> CustomAggregatingEnricher<S,T> newEnricher(
-            AttributeSensor<S> source, AttributeSensor<T> target, 
Function<Collection<S>, T> aggregator, S defaultVal) {
-        return newEnricher(Collections.<String,Object>emptyMap(), source, 
target, aggregator, defaultVal);
-    }
-    public static <S,T> CustomAggregatingEnricher<S,T> newEnricher(
-            AttributeSensor<S> source, AttributeSensor<T> target, 
Function<Collection<S>, T> aggregator) {
-        return newEnricher(Collections.<String,Object>emptyMap(), source, 
target, aggregator, null);
-    }
-    
-    /** 
-     * creates an enricher which sums over all children/members, 
-     * defaulting to excluding sensors which have not published anything (or 
published null), and null if there are no sensors; 
-     * this behaviour can be customised, both default value for sensors, and 
what to report if no sensors
-     * 
-     * Instead, consider calling:
-     * <pre>
-     * {@code
-     * Enrichers.Builder builder = Enrichers.builder()
-     *         .aggregating(source)
-     *         .publishing(target)
-     *         .computingSum()
-     *         
.defaultValueForUnreportedSensors(defaultValueForUnreportedSensors)
-     *         .valueToReportIfNoSensors(valueToReportIfNoSensors);
-     * 
-     * if (Boolean.TRUE.equals(allMembers)) builder.fromMembers();
-     * if (filter != null) builder.entityFilter(filter);
-     * if (hardCodedProducers != null) 
builder.fromHardcodedProducers(hardCodedProducers);
-     * 
-     * addEnricher(builder.build());
-     * }
-     * </pre>
-     *
-     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
-     */
-    public static <N extends Number, T extends Number> 
CustomAggregatingEnricher<N,T> newSummingEnricher(
-            Map<String,?> flags, AttributeSensor<N> source, final 
AttributeSensor<T> target, 
-            final N defaultValueForUnreportedSensors, final T 
valueToReportIfNoSensors) {
-        
-        Function<Collection<N>, T> aggregator = new Function<Collection<N>, 
T>() {
-                @Override public T apply(Collection<N> vals) {
-                    return sum(vals, defaultValueForUnreportedSensors, 
valueToReportIfNoSensors, target.getTypeToken());
-                }
-        };
-        return new CustomAggregatingEnricher<N,T>(flags, source, target, 
aggregator, defaultValueForUnreportedSensors);
-    }
-    
-    /** @see {@link #newSummingEnricher(Map, AttributeSensor, AttributeSensor, 
Number, Number)} */
-    public static <N extends Number> CustomAggregatingEnricher<N,N> 
newSummingEnricher(
-            AttributeSensor<N> source, AttributeSensor<N> target) {
-        return newSummingEnricher(Collections.<String,Object>emptyMap(), 
source, target, null, null);
-    }
-
-    /** creates an enricher which averages over all children/members, 
-     * defaulting to excluding sensors which have not published anything (or 
published null), and null if there are no sensors; 
-     * this behaviour can be customised, both default value for sensors, and 
what to report if no sensors
-     * 
-     * Instead, consider calling:
-     * <pre>
-     * {@code
-     * Enrichers.Builder builder = Enrichers.builder()
-     *         .aggregating(source)
-     *         .publishing(target)
-     *         .computingAverage()
-     *         
.defaultValueForUnreportedSensors(defaultValueForUnreportedSensors)
-     *         .valueToReportIfNoSensors(valueToReportIfNoSensors);
-     * 
-     * if (Boolean.TRUE.equals(allMembers)) builder.fromMembers();
-     * if (filter != null) builder.entityFilter(filter);
-     * if (hardCodedProducers != null) 
builder.fromHardcodedProducers(hardCodedProducers);
-     * 
-     * addEnricher(builder.build());
-     * }
-     * </pre>
-     *
-     * @deprecated since 0.7.0; use {@link Enrichers#builder()}
-     */
-    public static <N extends Number> CustomAggregatingEnricher<N,Double> 
newAveragingEnricher(
-            Map<String,?> flags, AttributeSensor<? extends N> source, final 
AttributeSensor<Double> target,
-            final N defaultValueForUnreportedSensors, final Double 
valueToReportIfNoSensors) {
-        Function<Collection<N>, Double> aggregator = new 
Function<Collection<N>, Double>() {
-            @Override public Double apply(Collection<N> vals) {
-                int count = count(vals, 
defaultValueForUnreportedSensors!=null);
-                return (count==0) ? valueToReportIfNoSensors : 
-                    (Double) ((sum(vals, defaultValueForUnreportedSensors, 0, 
TypeToken.of(Double.class)) / count));
-            }
-        };
-        return new CustomAggregatingEnricher<N,Double>(flags, source, target, 
aggregator, defaultValueForUnreportedSensors);
-    }
-
-    /** @see #newAveragingEnricher(Map, AttributeSensor, AttributeSensor, 
Number, Double) */
-    public static <N extends Number> CustomAggregatingEnricher<N,Double> 
newAveragingEnricher(
-            AttributeSensor<N> source, AttributeSensor<Double> target) {
-        return newAveragingEnricher(Collections.<String,Object>emptyMap(), 
source, target, null, null);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static <N extends Number> N cast(Number n, TypeToken<? extends N> 
numberType) {
-        return (N) TypeCoercions.castPrimitive(n, numberType.getRawType());
-    }
-
-    private static <N extends Number> N sum(Iterable<? extends Number> vals, 
Number valueIfNull, Number valueIfNone, TypeToken<N> type) {
-        double result = 0d;
-        int count = 0;
-        if (vals!=null) {
-            for (Number val : vals) { 
-                if (val!=null) {
-                    result += val.doubleValue();
-                    count++;
-                } else if (valueIfNull!=null) {
-                    result += valueIfNull.doubleValue();
-                    count++;
-                }
-            }
-        }
-        if (count==0) return cast(valueIfNone, type);
-        return cast(result, type);
-    }
-    
-    private static int count(Iterable<? extends Object> vals, boolean 
includeNullValues) {
-        int result = 0;
-        if (vals!=null) 
-            for (Object val : vals) 
-                if (val!=null || includeNullValues) result++;
-        return result;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherDynamicType.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherDynamicType.java
 
b/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherDynamicType.java
deleted file mode 100644
index 1363617..0000000
--- 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherDynamicType.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.enricher;
-
-import org.apache.brooklyn.api.sensor.Enricher;
-import org.apache.brooklyn.api.sensor.EnricherType;
-import org.apache.brooklyn.core.objs.BrooklynDynamicType;
-
-public class EnricherDynamicType extends BrooklynDynamicType<Enricher, 
AbstractEnricher> {
-
-    public EnricherDynamicType(Class<? extends Enricher> type) {
-        super(type);
-    }
-
-    public EnricherDynamicType(AbstractEnricher enricher) {
-        super(enricher);
-    }
-    
-    public EnricherType getSnapshot() {
-        return (EnricherType) super.getSnapshot();
-    }
-
-    @Override
-    protected EnricherTypeSnapshot newSnapshot() {
-        return new EnricherTypeSnapshot(name, value(configKeys));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherTypeSnapshot.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherTypeSnapshot.java
 
b/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherTypeSnapshot.java
deleted file mode 100644
index ed06de3..0000000
--- 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherTypeSnapshot.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.enricher;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.sensor.EnricherType;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.objs.BrooklynTypeSnapshot;
-
-public class EnricherTypeSnapshot extends BrooklynTypeSnapshot implements 
EnricherType {
-    private static final long serialVersionUID = 4670930188951106009L;
-    
-    EnricherTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) {
-        super(name, configKeys);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        return (obj instanceof EnricherTypeSnapshot) && super.equals(obj);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Enrichers.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Enrichers.java 
b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Enrichers.java
deleted file mode 100644
index 84e541d..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Enrichers.java
+++ /dev/null
@@ -1,824 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.enricher;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.api.sensor.Enricher;
-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.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.collections.MutableSet;
-import org.apache.brooklyn.util.core.flags.TypeCoercions;
-import org.apache.brooklyn.util.text.StringPredicates;
-import org.apache.brooklyn.util.text.Strings;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.reflect.TypeToken;
-
-public class Enrichers {
-
-    private Enrichers() {}
-    
-    public static InitialBuilder builder() {
-        return new InitialBuilder();
-    }
-
-    public abstract static class Builder<B extends Builder<B>> {
-        @SuppressWarnings("unchecked")
-        protected B self() {
-           return (B) this;
-        }
-    }
-    
-    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<? extends Enricher> build() {
-            EnricherSpec<? extends Enricher> spec = 
EnricherSpec.create(enricherType);
-            
-            String uniqueTag2 = uniqueTag;
-            if (uniqueTag2==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);
-        }
-        public PropagatorBuilder propagating(Iterable<? extends Sensor<?>> 
vals) {
-            return new PropagatorBuilder(vals);
-        }
-        public PropagatorBuilder propagating(Sensor<?>... vals) {
-            return new PropagatorBuilder(vals);
-        }
-        public PropagatorBuilder propagatingAll() {
-            return new PropagatorBuilder(true, null);
-        }
-        public PropagatorBuilder propagatingAllButUsualAnd(Sensor<?>... vals) {
-            return new PropagatorBuilder(true, 
ImmutableSet.<Sensor<?>>builder().addAll(Propagator.SENSORS_NOT_USUALLY_PROPAGATED).add(vals).build());
-        }
-        public PropagatorBuilder propagatingAllBut(Sensor<?>... vals) {
-            return new PropagatorBuilder(true, ImmutableSet.copyOf(vals));
-        }
-        public PropagatorBuilder propagatingAllBut(Iterable<? extends 
Sensor<?>> vals) {
-            return new PropagatorBuilder(true, vals);
-        }
-        
-        /**
-         * Builds an enricher which transforms a given sensor:
-         * <li> applying a (required) function ({@link 
TransformerBuilder#computing(Function)}, or
-         *      {@link AbstractAggregatorBuilder#computingAverage()}/
-         *      {@link AbstractAggregatorBuilder#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)} */
-        @SafeVarargs
-        public final <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
-         **/
-        public <S,TKey,TVal> UpdatingMapBuilder<S, TKey, TVal> 
updatingMap(AttributeSensor<Map<TKey,TVal>> target) {
-            return new UpdatingMapBuilder<S, TKey, TVal>(target);
-        }
-        /** creates a {@link org.apache.brooklyn.sensor.enricher.Joiner} 
enricher builder
-         * which joins entries in a list to produce a String
-         **/
-        public JoinerBuilder joining(AttributeSensor<?> source) {
-            return new JoinerBuilder(source);
-        }
-    }
-
-
-    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;
-        /** @deprecated since 0.7.0, kept for backwards compatibility for 
rebind, but not used otherwise */
-        @Deprecated protected Function<? super Collection<S>, ? extends T> 
computing;
-        // use supplier so latest values of other fields can be used
-        protected Supplier<Function<? super Collection<S>, ? extends T>> 
computingSupplier;
-        protected Boolean fromMembers;
-        protected Boolean fromChildren;
-        protected Boolean excludingBlank;
-        protected ImmutableSet<Entity> fromHardcodedProducers;
-        protected Predicate<? super Entity> entityFilter;
-        protected Predicate<Object> valueFilter;
-        protected Object defaultValueForUnreportedSensors;
-        protected Object valueToReportIfNoSensors;
-        
-        public AbstractAggregatorBuilder(AttributeSensor<S> aggregating) {
-            super(Aggregator.class);
-            this.aggregating = aggregating;
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public <T2 extends T> AggregatorBuilder<S,T2> 
publishing(AttributeSensor<? extends T2> val) {
-            this.publishing = (AttributeSensor) checkNotNull(val);
-            return (AggregatorBuilder) self();
-        }
-        public B from(Entity val) {
-            this.fromEntity = checkNotNull(val);
-            return self();
-        }
-        public B fromMembers() {
-            this.fromMembers = true;
-            return self();
-        }
-        public B fromChildren() {
-            this.fromChildren = true;
-            return self();
-        }
-        public B fromHardcodedProducers(Iterable<? extends Entity> val) {
-            this.fromHardcodedProducers = ImmutableSet.copyOf(val);
-            return self();
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public B computing(Function<? super Collection<S>, ? extends T> val) {
-            this.computingSupplier = 
(Supplier)Suppliers.ofInstance(checkNotNull(val));
-            return self();
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes", "unused" })
-        private B computingSumLegacy() {
-            // since 0.7.0, kept in case we need to rebind to this
-            Function<Collection<S>, Number> function = new 
Function<Collection<S>, Number>()  {
-                @Override public Number apply(Collection<S> input) {
-                    return sum((Collection)input, 
(Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, 
(TypeToken) publishing.getTypeToken());
-                }};
-            this.computing((Function)function);
-            return self();
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes", "unused" })
-        private B computingAverageLegacy() {
-            // since 0.7.0, kept in case we need to rebind to this
-            Function<Collection<S>, Number> function = new 
Function<Collection<S>, Number>() {
-                @Override public Number apply(Collection<S> input) {
-                    return average((Collection)input, 
(Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, 
(TypeToken) publishing.getTypeToken());
-                }};
-            this.computing((Function)function);
-            return self();
-        }
-        public B computingSum() {
-            this.computingSupplier = new Supplier<Function<? super 
Collection<S>, ? extends T>>() {
-                @Override
-                @SuppressWarnings({ "unchecked", "rawtypes" })
-                public Function<? super Collection<S>, ? extends T> get() {
-                    // relies on TypeCoercion of result from Number to T, and 
type erasure for us to get away with it!
-                    return (Function)new 
ComputingSum((Number)defaultValueForUnreportedSensors, 
(Number)valueToReportIfNoSensors, publishing.getTypeToken());
-                }
-            };
-            return self();
-        }
-
-        public B computingAverage() {
-            this.computingSupplier = new Supplier<Function<? super 
Collection<S>, ? extends T>>() {
-                @Override
-                @SuppressWarnings({ "unchecked", "rawtypes" })
-                public Function<? super Collection<S>, ? extends T> get() {
-                    // relies on TypeCoercion of result from Number to T, and 
type erasure for us to get away with it!
-                    return (Function)new 
ComputingAverage((Number)defaultValueForUnreportedSensors, 
(Number)valueToReportIfNoSensors, publishing.getTypeToken());
-                }
-            };
-            return self();
-        }
-        public B defaultValueForUnreportedSensors(S val) {
-            this.defaultValueForUnreportedSensors = val;
-            return self();
-        }
-        public B valueToReportIfNoSensors(Object val) {
-            this.valueToReportIfNoSensors = val;
-            return self();
-        }
-        public B entityFilter(Predicate<? super Entity> val) {
-            this.entityFilter = val;
-            return self();
-        }
-        public B excludingBlank() {
-            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)) {
-                valueFilter = new Predicate<Object>() {
-                    @Override public boolean apply(Object input) {
-                        return (input != null) &&
-                                ((input instanceof CharSequence) ? 
Strings.isNonBlank((CharSequence)input) : true);
-                    }
-                };
-                // above kept for deserialization; not sure necessary
-                valueFilter = StringPredicates.isNonBlank(); 
-            } else {
-                valueFilter = null;
-            }
-            // FIXME excludingBlank; use valueFilter? exclude means ignored 
entirely or substituted for defaultMemberValue?
-            return super.build().configure(MutableMap.builder()
-                            .putIfNotNull(Aggregator.PRODUCER, fromEntity)
-                            .put(Aggregator.TARGET_SENSOR, publishing)
-                            .put(Aggregator.SOURCE_SENSOR, aggregating)
-                            .putIfNotNull(Aggregator.FROM_CHILDREN, 
fromChildren)
-                            .putIfNotNull(Aggregator.FROM_MEMBERS, fromMembers)
-                            .putIfNotNull(Aggregator.TRANSFORMATION, 
computingSupplier.get())
-                            .putIfNotNull(Aggregator.FROM_HARDCODED_PRODUCERS, 
fromHardcodedProducers)
-                            .putIfNotNull(Aggregator.ENTITY_FILTER, 
entityFilter)
-                            .putIfNotNull(Aggregator.VALUE_FILTER, valueFilter)
-                            .putIfNotNull(Aggregator.DEFAULT_MEMBER_VALUE, 
defaultValueForUnreportedSensors)
-                            .build());
-        }
-        
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(this)
-                    .omitNullValues()
-                    .add("aggregating", aggregating)
-                    .add("publishing", publishing)
-                    .add("fromEntity", fromEntity)
-                    .add("computing", computingSupplier)
-                    .add("fromMembers", fromMembers)
-                    .add("fromChildren", fromChildren)
-                    .add("excludingBlank", excludingBlank)
-                    .add("fromHardcodedProducers", fromHardcodedProducers)
-                    .add("entityFilter", entityFilter)
-                    .add("valueFilter", valueFilter)
-                    .add("defaultValueForUnreportedSensors", 
defaultValueForUnreportedSensors)
-                    .add("valueToReportIfNoSensors", valueToReportIfNoSensors)
-                    .toString();
-        }
-    }
-    
-    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;
-        protected Function<? super Collection<S>, ? extends T> computing;
-        protected Boolean excludingBlank;
-        protected Object valueToReportIfNoSensors;
-        protected Predicate<Object> valueFilter;
-
-        // For summing/averaging
-        protected Object defaultValueForUnreportedSensors;
-        
-        @SafeVarargs
-        public AbstractCombinerBuilder(AttributeSensor<? extends S>... vals) {
-            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);
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public <T2 extends T> CombinerBuilder<S,T2> 
publishing(AttributeSensor<? extends T2> val) {
-            this.publishing = (AttributeSensor) checkNotNull(val);
-            return (CombinerBuilder) this;
-        }
-        public B from(Entity val) {
-            this.fromEntity = checkNotNull(val);
-            return self();
-        }
-        public B computing(Function<? super Collection<S>, ? extends T> val) {
-            this.computing = checkNotNull(val);
-            return self();
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public B computingSum() {
-            Function<Collection<S>, Number> function = new 
Function<Collection<S>, Number>() {
-                @Override public Number apply(Collection<S> input) {
-                    return sum((Collection)input, 
(Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, 
(TypeToken) publishing.getTypeToken());
-                }};
-            this.computing((Function)function);
-            return self();
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public B computingAverage() {
-            Function<Collection<S>, Number> function = new 
Function<Collection<S>, Number>() {
-                @Override public Number apply(Collection<S> input) {
-                    return average((Collection)input, 
(Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, 
(TypeToken) publishing.getTypeToken());
-                }};
-            this.computing((Function)function);
-            return self();
-        }
-        public B defaultValueForUnreportedSensors(Object val) {
-            this.defaultValueForUnreportedSensors = val;
-            return self();
-        }
-        public B valueToReportIfNoSensors(Object val) {
-            this.valueToReportIfNoSensors = val;
-            return self();
-        }
-        public B excludingBlank() {
-            this.excludingBlank = true;
-            return self();
-        }
-        @Override
-        protected String getDefaultUniqueTag() {
-            if (publishing==null) return null;
-            return "combiner:"+publishing.getName();
-        }
-        public EnricherSpec<?> build() {
-            return super.build().configure(MutableMap.builder()
-                            .putIfNotNull(Combiner.PRODUCER, fromEntity)
-                            .put(Combiner.TARGET_SENSOR, publishing)
-                            .put(Combiner.SOURCE_SENSORS, combining)
-                            .putIfNotNull(Combiner.TRANSFORMATION, computing)
-                            .putIfNotNull(Combiner.VALUE_FILTER, valueFilter)
-                            .build());
-        }
-        
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(this)
-                    .omitNullValues()
-                    .add("combining", combining)
-                    .add("publishing", publishing)
-                    .add("fromEntity", fromEntity)
-                    .add("computing", computing)
-                    .add("excludingBlank", excludingBlank)
-                    .add("valueToReportIfNoSensors", valueToReportIfNoSensors)
-                    .add("valueFilter", valueFilter)
-                    .toString();
-        }
-    }
-
-    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;
-        protected Function<? super S, ?> computing;
-        protected Function<? super SensorEvent<S>, ?> computingFromEvent;
-
-        public AbstractTransformerBuilder(AttributeSensor<S> val) {
-            super(Transformer.class);
-            this.transforming = checkNotNull(val);
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public <T2 extends T> TransformerBuilder<S,T2> 
publishing(AttributeSensor<? extends T2> val) {
-            this.publishing = (AttributeSensor) checkNotNull(val);
-            return (TransformerBuilder) this;
-        }
-        public B from(Entity val) {
-            this.fromEntity = checkNotNull(val);
-            return self();
-        }
-        public B computing(Function<? super S, ? extends T> val) {
-            this.computing = checkNotNull(val);
-            return self();
-        }
-        public B computingFromEvent(Function<? super SensorEvent<S>, ? extends 
T> val) {
-            this.computingFromEvent = checkNotNull(val);
-            return self();
-        }
-        @Override
-        protected String getDefaultUniqueTag() {
-            if (publishing==null) return null;
-            return "transformer:"+publishing.getName();
-        }
-        public EnricherSpec<?> build() {
-            return super.build().configure(MutableMap.builder()
-                            .putIfNotNull(Transformer.PRODUCER, fromEntity)
-                            .put(Transformer.TARGET_SENSOR, publishing)
-                            .put(Transformer.SOURCE_SENSOR, transforming)
-                            
.putIfNotNull(Transformer.TRANSFORMATION_FROM_VALUE, computing)
-                            
.putIfNotNull(Transformer.TRANSFORMATION_FROM_EVENT, computingFromEvent)
-                            .build());
-        }
-        
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(this)
-                    .omitNullValues()
-                    .add("publishing", publishing)
-                    .add("transforming", transforming)
-                    .add("fromEntity", fromEntity)
-                    .add("computing", computing)
-                    .toString();
-        }
-    }
-
-    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;
-            this.propagatingAllBut = null;
-        }
-        public AbstractPropagatorBuilder(Iterable<? extends Sensor<?>> vals) {
-            this(newIdentityMap(ImmutableSet.copyOf(vals)));
-        }
-        public AbstractPropagatorBuilder(Sensor<?>... vals) {
-            this(newIdentityMap(ImmutableSet.copyOf(vals)));
-        }
-        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)");
-            this.propagating = null;
-            this.propagatingAll = true;
-            this.propagatingAllBut = (butVals == null || 
Iterables.isEmpty(butVals)) ? null: butVals;
-        }
-        public B from(Entity val) {
-            this.fromEntity = checkNotNull(val);
-            return self();
-        }
-        @Override
-        protected String getDefaultUniqueTag() {
-            List<String> summary = MutableList.of();
-            if (propagating!=null) {
-                for (Map.Entry<? extends Sensor<?>, ? extends Sensor<?>> 
entry: propagating.entrySet()) {
-                    if 
(entry.getKey().getName().equals(entry.getValue().getName()))
-                        summary.add(entry.getKey().getName());
-                    else
-                        
summary.add(entry.getKey().getName()+"->"+entry.getValue().getName());
-                }
-            }
-            if (Boolean.TRUE.equals(propagatingAll))
-                summary.add("ALL");
-            if (propagatingAllBut!=null && 
!Iterables.isEmpty(propagatingAllBut)) {
-                List<String> allBut = MutableList.of();
-                for (Sensor<?> s: propagatingAllBut) allBut.add(s.getName());
-                
summary.add("ALL_BUT:"+com.google.common.base.Joiner.on(",").join(allBut));
-            }
-            
-            return 
"propagating["+fromEntity.getId()+":"+com.google.common.base.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)
-                            .putIfNotNull(Propagator.PROPAGATING_ALL_BUT, 
propagatingAllBut)
-                            .build());
-        }
-        
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(this)
-                    .omitNullValues()
-                    .add("fromEntity", fromEntity)
-                    .add("propagating", propagating)
-                    .add("propagatingAll", propagatingAll)
-                    .add("propagatingAllBut", propagatingAllBut)
-                    .toString();
-        }
-    }
-
-    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;
-        protected Function<S, ? extends TVal> computing;
-        protected Boolean removingIfResultIsNull;
-        
-        public AbstractUpdatingMapBuilder(AttributeSensor<Map<TKey,TVal>> 
target) {
-            super(UpdatingMap.class);
-            this.targetSensor = target;
-        }
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public <S2 extends S> UpdatingMapBuilder<S2,TKey,TVal> 
from(AttributeSensor<S2> fromSensor) {
-            this.fromSensor = checkNotNull(fromSensor);
-            return (UpdatingMapBuilder) this;
-        }
-        public B computing(Function<S,? extends TVal> val) {
-            this.computing = checkNotNull(val);
-            return self();
-        }
-        /** sets an explicit key to use; defaults to using the name of the 
source sensor specified in {@link #from(AttributeSensor)} */
-        public B key(TKey key) {
-            this.key = key;
-            return self();
-        }
-        /** sets explicit behaviour for treating <code>null</code> return 
values;
-         * default is to remove */
-        public B removingIfResultIsNull(boolean val) {
-            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 super.build().configure(MutableMap.builder()
-                            .put(UpdatingMap.TARGET_SENSOR, targetSensor)
-                            .put(UpdatingMap.SOURCE_SENSOR, fromSensor)
-                            .putIfNotNull(UpdatingMap.KEY_IN_TARGET_SENSOR, 
key)
-                            .put(UpdatingMap.COMPUTING, computing)
-                            
.putIfNotNull(UpdatingMap.REMOVING_IF_RESULT_IS_NULL, removingIfResultIsNull)
-                            .build());
-        }
-        
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(this)
-                    .omitNullValues()
-                    .add("publishing", targetSensor)
-                    .add("fromSensor", fromSensor)
-                    .add("key", key)
-                    .add("computing", computing)
-                    .add("removingIfResultIsNull", removingIfResultIsNull)
-                    .toString();
-        }
-    }
-
-    protected abstract static class AbstractJoinerBuilder<B extends 
AbstractJoinerBuilder<B>> extends AbstractEnricherBuilder<B> {
-        protected final AttributeSensor<?> transforming;
-        protected AttributeSensor<String> publishing;
-        protected Entity fromEntity;
-        protected String separator;
-        protected Boolean quote;
-        protected Integer minimum;
-        protected Integer maximum;
-
-        public AbstractJoinerBuilder(AttributeSensor<?> source) {
-            super(Joiner.class);
-            this.transforming = checkNotNull(source);
-        }
-        public B publishing(AttributeSensor<String> target) {
-            this.publishing = checkNotNull(target);
-            return self();
-        }
-        public B separator(String separator) {
-            this.separator = separator;
-            return self();
-        }
-        public B quote(Boolean quote) {
-            this.quote = quote;
-            return self();
-        }
-        public B minimum(Integer minimum) {
-            this.minimum = minimum;
-            return self();
-        }
-        public B maximum(Integer maximum) {
-            this.maximum = maximum;
-            return self();
-        }
-        @Override
-        protected String getDefaultUniqueTag() {
-            if (transforming==null || publishing==null) return null;
-            return "joiner:"+transforming.getName()+"->"+publishing.getName();
-        }
-        public EnricherSpec<?> build() {
-            return super.build().configure(MutableMap.builder()
-                            .putIfNotNull(Joiner.PRODUCER, fromEntity)
-                            .put(Joiner.TARGET_SENSOR, publishing)
-                            .put(Joiner.SOURCE_SENSOR, transforming)
-                            .putIfNotNull(Joiner.SEPARATOR, separator)
-                            .putIfNotNull(Joiner.QUOTE, quote)
-                            .putIfNotNull(Joiner.MINIMUM, minimum)
-                            .putIfNotNull(Joiner.MAXIMUM, maximum)
-                            .build());
-        }
-        
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(this)
-                    .omitNullValues()
-                    .add("publishing", publishing)
-                    .add("transforming", transforming)
-                    .add("separator", separator)
-                    .toString();
-        }
-    }
-    
-    public static class InitialBuilder extends 
AbstractInitialBuilder<InitialBuilder> {
-    }
-
-    public static class AggregatorBuilder<S, T> extends 
AbstractAggregatorBuilder<S, T, AggregatorBuilder<S, T>> {
-        public AggregatorBuilder(AttributeSensor<S> aggregating) {
-            super(aggregating);
-        }
-    }
-
-    public static class PropagatorBuilder extends 
AbstractPropagatorBuilder<PropagatorBuilder> {
-        public PropagatorBuilder(Map<? extends Sensor<?>, ? extends Sensor<?>> 
vals) {
-            super(vals);
-        }
-        public PropagatorBuilder(Iterable<? extends Sensor<?>> vals) {
-            super(vals);
-        }
-        public PropagatorBuilder(Sensor<?>... vals) {
-            super(vals);
-        }
-        PropagatorBuilder(boolean propagatingAll, Iterable<? extends 
Sensor<?>> butVals) {
-            super(propagatingAll, butVals);
-        }
-    }
-
-    public static class CombinerBuilder<S, T> extends 
AbstractCombinerBuilder<S, T, CombinerBuilder<S, T>> {
-        @SafeVarargs
-        public CombinerBuilder(AttributeSensor<? extends S>... vals) {
-            super(vals);
-        }
-        public CombinerBuilder(Collection<AttributeSensor<? extends S>> vals) {
-            super(vals);
-        }
-    }
-
-    public static class TransformerBuilder<S, T> extends 
AbstractTransformerBuilder<S, T, TransformerBuilder<S, T>> {
-        public TransformerBuilder(AttributeSensor<S> val) {
-            super(val);
-        }
-    }
-
-    public static class UpdatingMapBuilder<S, TKey, TVal> extends 
AbstractUpdatingMapBuilder<S, TKey, TVal, UpdatingMapBuilder<S, TKey, TVal>> {
-        public UpdatingMapBuilder(AttributeSensor<Map<TKey,TVal>> val) {
-            super(val);
-        }
-    }
-
-    public static class JoinerBuilder extends 
AbstractJoinerBuilder<JoinerBuilder> {
-        public JoinerBuilder(AttributeSensor<?> source) {
-            super(source);
-        }
-    }
-
-    @Beta
-    private abstract static class ComputingNumber<T extends Number> implements 
Function<Collection<T>, T> {
-        protected final Number defaultValueForUnreportedSensors;
-        protected final Number valueToReportIfNoSensors;
-        protected final TypeToken<T> typeToken;
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        public ComputingNumber(Number defaultValueForUnreportedSensors, Number 
valueToReportIfNoSensors, TypeToken<T> typeToken) {
-            this.defaultValueForUnreportedSensors = 
defaultValueForUnreportedSensors;
-            this.valueToReportIfNoSensors = valueToReportIfNoSensors;
-            if (typeToken!=null && 
TypeToken.of(Number.class).isAssignableFrom(typeToken.getType())) {
-                this.typeToken = typeToken;
-            } else if (typeToken==null || 
typeToken.isAssignableFrom(Number.class)) {
-                // use double if e.g. Object is supplied
-                this.typeToken = (TypeToken)TypeToken.of(Double.class);
-            } else {
-                throw new IllegalArgumentException("Type "+typeToken+" is not 
valid for "+this);
-            }
-        }
-        @Override public abstract T apply(Collection<T> input);
-    }
-
-    @Beta
-    public static class ComputingSum<T extends Number> extends 
ComputingNumber<T> {
-        public ComputingSum(Number defaultValueForUnreportedSensors, Number 
valueToReportIfNoSensors, TypeToken<T> typeToken) {
-            super(defaultValueForUnreportedSensors, valueToReportIfNoSensors, 
typeToken);
-        }
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        @Override public T apply(Collection<T> input) {
-            return (T) sum((Collection)input, 
(Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, 
typeToken);
-        }
-    }
-
-    @Beta
-    public static class ComputingAverage<T extends Number> extends 
ComputingNumber<T> {
-        public ComputingAverage(Number defaultValueForUnreportedSensors, 
Number valueToReportIfNoSensors, TypeToken<T> typeToken) {
-            super(defaultValueForUnreportedSensors, valueToReportIfNoSensors, 
typeToken);
-        }
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        @Override public T apply(Collection<T> input) {
-            return (T) average((Collection)input, 
(Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, 
typeToken);
-        }
-    }
-
-    protected static <T extends Number> T average(Collection<T> vals, Number 
defaultValueForUnreportedSensors, Number valueToReportIfNoSensors, TypeToken<T> 
type) {
-        Double doubleValueToReportIfNoSensors = (valueToReportIfNoSensors == 
null) ? null : valueToReportIfNoSensors.doubleValue();
-        int count = count(vals, defaultValueForUnreportedSensors!=null);
-        Double result = (count==0) ? doubleValueToReportIfNoSensors : 
-            (Double) ((sum(vals, defaultValueForUnreportedSensors, 0, 
TypeToken.of(Double.class)) / count));
-        
-        return cast(result, type);
-    }
-    
-    @SuppressWarnings("unchecked")
-    protected static <N extends Number> N cast(Number n, TypeToken<? extends 
N> numberType) {
-        return (N) TypeCoercions.castPrimitive(n, numberType.getRawType());
-    }
-
-    @Beta  //may be moved
-    public static <N extends Number> N sum(Iterable<? extends Number> vals, 
Number valueIfNull, Number valueIfNone, TypeToken<N> type) {
-        double result = 0d;
-        int count = 0;
-        if (vals!=null) {
-            for (Number val : vals) { 
-                if (val!=null) {
-                    result += val.doubleValue();
-                    count++;
-                } else if (valueIfNull!=null) {
-                    result += valueIfNull.doubleValue();
-                    count++;
-                }
-            }
-        }
-        if (count==0) return cast(valueIfNone, type);
-        return cast(result, type);
-    }
-    
-    protected static int count(Iterable<? extends Object> vals, boolean 
includeNullValues) {
-        int result = 0;
-        if (vals != null) 
-            for (Object val : vals) 
-                if (val!=null || includeNullValues) result++;
-        return result;
-    }
-    
-    private static <T> Map<T,T> newIdentityMap(Set<T> keys) {
-        Map<T,T> result = Maps.newLinkedHashMap();
-        for (T key : keys) {
-            result.put(key, key);
-        }
-        return result;
-    }
-    
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java 
b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java
deleted file mode 100644
index c6d9329..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.enricher;
-
-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.sensor.BasicSensorEvent;
-import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-import org.apache.brooklyn.util.text.StringEscapes;
-import org.apache.brooklyn.util.text.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.reflect.TypeToken;
-
-//@Catalog(name="Transformer", description="Transforms attributes of an 
entity; see Enrichers.builder().transforming(...)")
-@SuppressWarnings("serial")
-public class Joiner<T> extends AbstractEnricher implements 
SensorEventListener<T> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(Joiner.class);
-
-    public static ConfigKey<Entity> PRODUCER = 
ConfigKeys.newConfigKey(Entity.class, "enricher.producer");
-    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");
-    @SetFromFlag("separator")
-    public static ConfigKey<String> SEPARATOR = 
ConfigKeys.newStringConfigKey("enricher.joiner.separator", "Separator string to 
insert between each argument", ",");
-    @SetFromFlag("quote")
-    public static ConfigKey<Boolean> QUOTE = 
ConfigKeys.newBooleanConfigKey("enricher.joiner.quote", "Whether to bash-escape 
each parameter and wrap in double-quotes, defaulting to true", true);
-    @SetFromFlag("minimum")
-    public static ConfigKey<Integer> MINIMUM = 
ConfigKeys.newIntegerConfigKey("enricher.joiner.minimum", "Minimum number of 
elements to join; if fewer than this, sets null; default 0 (no minimum)");
-    @SetFromFlag("maximum")
-    public static ConfigKey<Integer> MAXIMUM = 
ConfigKeys.newIntegerConfigKey("enricher.joiner.maximum", "Maximum number of 
elements to join; default null means all elements always taken");
-    
-    protected Entity producer;
-    protected AttributeSensor<T> sourceSensor;
-    protected Sensor<String> targetSensor;
-
-    public Joiner() {
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-
-        this.producer = getConfig(PRODUCER) == null ? entity: 
getConfig(PRODUCER);
-        this.sourceSensor = (AttributeSensor<T>) 
getRequiredConfig(SOURCE_SENSOR);
-        this.targetSensor = (Sensor<String>) getRequiredConfig(TARGET_SENSOR);
-        
-        subscribe(producer, sourceSensor, this);
-        
-        Object value = producer.getAttribute((AttributeSensor<?>)sourceSensor);
-        // TODO would be useful to have a convenience to 
"subscribeAndThenIfItIsAlreadySetRunItOnce"
-        if (value!=null) {
-            onEvent(new BasicSensorEvent(sourceSensor, producer, value, -1));
-        }
-    }
-
-    @Override
-    public void onEvent(SensorEvent<T> event) {
-        emit(targetSensor, compute(event));
-    }
-
-    protected Object compute(SensorEvent<T> event) {
-        Object v = event.getValue();
-        Object result = null;
-        if (v!=null) {
-            if (v instanceof Map) {
-                v = ((Map<?,?>)v).values();
-            }
-            if (!(v instanceof Iterable)) {
-                LOG.warn("Enricher "+this+" received a non-iterable value 
"+v.getClass()+" "+v+"; refusing to join");
-            } else {
-                MutableList<Object> c1 = MutableList.of();
-                Integer maximum = getConfig(MAXIMUM);
-                for (Object ci: (Iterable<?>)v) {
-                    if (maximum!=null && maximum>=0) {
-                        if (c1.size()>=maximum) break;
-                    }
-                    c1.appendIfNotNull(Strings.toString(ci));
-                }
-                Integer minimum = getConfig(MINIMUM);
-                if (minimum!=null && c1.size() < minimum) {
-                    // use default null return value
-                } else {
-                    if (getConfig(QUOTE)) {
-                        MutableList<Object> c2 = MutableList.of();
-                        for (Object ci: c1) {
-                            
c2.add(StringEscapes.BashStringEscapes.wrapBash((String)ci));
-                        }
-                        c1 = c2;
-                    }
-                    result = Strings.join(c1, getConfig(SEPARATOR));
-                }
-            }
-        }
-        if (LOG.isTraceEnabled())
-            LOG.trace("Enricher "+this+" computed "+result+" from "+event);
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Propagator.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Propagator.java 
b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Propagator.java
deleted file mode 100644
index 2d74848..0000000
--- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Propagator.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.sensor.enricher;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-
-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.entity.Attributes;
-import org.apache.brooklyn.util.collections.MutableMap;
-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.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.reflect.TypeToken;
-
-@SuppressWarnings("serial")
-//@Catalog(name="Propagator", description="Propagates attributes from one 
entity to another; see Enrichers.builder().propagating(...)")
-public class Propagator extends AbstractEnricher implements 
SensorEventListener<Object> {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(Propagator.class);
-
-    public static final Set<Sensor<?>> SENSORS_NOT_USUALLY_PROPAGATED = 
ImmutableSet.<Sensor<?>>of(
-        Attributes.SERVICE_UP, Attributes.SERVICE_NOT_UP_INDICATORS, 
-        Attributes.SERVICE_STATE_ACTUAL, Attributes.SERVICE_STATE_EXPECTED, 
Attributes.SERVICE_PROBLEMS);
-
-    @SetFromFlag("producer")
-    public static ConfigKey<Entity> PRODUCER = 
ConfigKeys.newConfigKey(Entity.class, "enricher.producer");
-
-    @SetFromFlag("propagatingAllBut")
-    public static ConfigKey<Collection<Sensor<?>>> PROPAGATING_ALL_BUT = 
ConfigKeys.newConfigKey(new TypeToken<Collection<Sensor<?>>>() {}, 
"enricher.propagating.propagatingAllBut");
-
-    @SetFromFlag("propagatingAll")
-    public static ConfigKey<Boolean> PROPAGATING_ALL = 
ConfigKeys.newBooleanConfigKey("enricher.propagating.propagatingAll");
-
-    @SetFromFlag("propagating")
-    public static ConfigKey<Collection<? extends Sensor<?>>> PROPAGATING = 
ConfigKeys.newConfigKey(new TypeToken<Collection<? extends Sensor<?>>>() {}, 
"enricher.propagating.inclusions");
-
-    @SetFromFlag("sensorMapping")
-    public static ConfigKey<Map<? extends Sensor<?>, ? extends Sensor<?>>> 
SENSOR_MAPPING = ConfigKeys.newConfigKey(new TypeToken<Map<? extends Sensor<?>, 
? extends Sensor<?>>>() {}, "enricher.propagating.sensorMapping");
-
-    protected Entity producer;
-    protected Map<? extends Sensor<?>, ? extends Sensor<?>> sensorMapping;
-    protected boolean propagatingAll;
-    protected Collection<Sensor<?>> propagatingAllBut;
-    protected Predicate<Sensor<?>> sensorFilter;
-
-    public Propagator() {
-    }
-
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-        
-        this.producer = getConfig(PRODUCER) == null ? entity : 
getConfig(PRODUCER);
-        boolean sensorMappingSet = getConfig(SENSOR_MAPPING)!=null;
-        MutableMap<Sensor<?>,Sensor<?>> sensorMappingTemp = 
MutableMap.copyOf(getConfig(SENSOR_MAPPING)); 
-        this.propagatingAll = Boolean.TRUE.equals(getConfig(PROPAGATING_ALL)) 
|| getConfig(PROPAGATING_ALL_BUT)!=null;
-        
-        if (getConfig(PROPAGATING) != null) {
-            if (propagatingAll) {
-                throw new IllegalStateException("Propagator enricher "+this+" 
must not have 'propagating' set at same time as either 'propagatingAll' or 
'propagatingAllBut'");
-            }
-            
-            for (Object sensorO : getConfig(PROPAGATING)) {
-                Sensor<?> sensor = 
Tasks.resolving(sensorO).as(Sensor.class).timeout(ValueResolver.REAL_QUICK_WAIT).context(producer).get();
-                if (!sensorMappingTemp.containsKey(sensor)) {
-                    sensorMappingTemp.put(sensor, sensor);
-                }
-            }
-            this.sensorMapping = ImmutableMap.copyOf(sensorMappingTemp);
-            this.sensorFilter = new Predicate<Sensor<?>>() {
-                @Override public boolean apply(Sensor<?> input) {
-                    // TODO kept for deserialization of inner classes, but 
shouldn't be necessary, as with other inner classes (qv);
-                    // NB: previously this did this check:
-//                    return input != null && 
sensorMapping.keySet().contains(input);
-                    // but those clauses seems wrong (when would input be 
null?) and unnecessary (we are doing an explicit subscribe in this code path) 
-                    return true;
-                }
-            };
-        } else if (sensorMappingSet) {
-            if (propagatingAll) {
-                throw new IllegalStateException("Propagator enricher "+this+" 
must not have 'sensorMapping' set at same time as either 'propagatingAll' or 
'propagatingAllBut'");
-            }
-            this.sensorMapping = ImmutableMap.copyOf(sensorMappingTemp);
-            this.sensorFilter = Predicates.alwaysTrue();
-        } else {
-            this.sensorMapping = ImmutableMap.<Sensor<?>, Sensor<?>>of();
-            if (!propagatingAll) {
-                // default if nothing specified is to do all but the ones not 
usually propagated
-                propagatingAll = true;
-                // user specified nothing, so *set* the all_but to the default 
set
-                // if desired, we could allow this to be dynamically 
reconfigurable, remove this field and always look up;
-                // slight performance hit (always looking up), and might need 
to recompute subscriptions, so not supported currently
-                // TODO this default is @Beta behaviour! -- maybe better to 
throw?
-                propagatingAllBut = SENSORS_NOT_USUALLY_PROPAGATED;
-            } else {
-                propagatingAllBut = getConfig(PROPAGATING_ALL_BUT);
-            }
-            this.sensorFilter = new Predicate<Sensor<?>>() {
-                @Override public boolean apply(Sensor<?> input) {
-                    Collection<Sensor<?>> exclusions = propagatingAllBut;
-                    // TODO this anonymous inner class and getConfig check 
kept should be removed / confirmed for rebind compatibility.
-                    // we *should* be regenerating these fields on each rebind 
(calling to this method), 
-                    // so serialization of this class shouldn't be needed (and 
should be skipped), but that needs to be checked.
-                    if (propagatingAllBut==null) exclusions = 
getConfig(PROPAGATING_ALL_BUT);
-                    return input != null && (exclusions==null || 
!exclusions.contains(input));
-                }
-            };
-        }
-            
-        Preconditions.checkState(propagatingAll ^ sensorMapping.size() > 0,
-                "Nothing to propagate; detected: propagatingAll (%s, excluding 
%s), sensorMapping (%s)", propagatingAll, getConfig(PROPAGATING_ALL_BUT), 
sensorMapping);
-
-        if (propagatingAll) {
-            subscribe(producer, null, this);
-        } else {
-            for (Sensor<?> sensor : sensorMapping.keySet()) {
-                subscribe(producer, sensor, this);
-            }
-        }
-        
-        emitAllAttributes();
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Override
-    public void onEvent(SensorEvent<Object> event) {
-        // propagate upwards
-        Sensor<?> sourceSensor = event.getSensor();
-        Sensor<?> destinationSensor = getDestinationSensor(sourceSensor);
-        
-        if (!sensorFilter.apply(sourceSensor)) {
-            return; // ignoring excluded sensor
-        }
-        
-        if (LOG.isTraceEnabled()) LOG.trace("enricher {} got {}, propagating 
via {}{}", 
-                new Object[] {this, event, entity, (sourceSensor == 
destinationSensor ? "" : " (as "+destinationSensor+")")});
-        
-        emit((Sensor)destinationSensor, event.getValue());
-    }
-
-    /** useful once sensors are added to emit all values */
-    public void emitAllAttributes() {
-        emitAllAttributes(false);
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public void emitAllAttributes(boolean includeNullValues) {
-        Iterable<? extends Sensor<?>> sensorsToPopulate = propagatingAll 
-                ? Iterables.filter(producer.getEntityType().getSensors(), 
sensorFilter)
-                : sensorMapping.keySet();
-
-        for (Sensor<?> s : sensorsToPopulate) {
-            if (s instanceof AttributeSensor) {
-                AttributeSensor destinationSensor = (AttributeSensor<?>) 
getDestinationSensor(s);
-                Object v = producer.getAttribute((AttributeSensor<?>)s);
-                // TODO we should keep a timestamp for the source sensor and 
echo it 
-                // (this pretends timestamps are current, which probably isn't 
the case when we are propagating)
-                if (v != null || includeNullValues) 
entity.setAttribute(destinationSensor, v);
-            }
-        }
-    }
-
-    private Sensor<?> getDestinationSensor(Sensor<?> sourceSensor) {
-        return sensorMapping.containsKey(sourceSensor) ? 
sensorMapping.get(sourceSensor): sourceSensor;
-    }
-}

Reply via email to